Optimización Interbase
Recomendaciones obtenidas de los siguientes artículos:
Optimization I: Optimizing InterBase Applications
Optimization II: Optimizing InterBase SQL and Metadata
Optimization III: Selecting and Configuring InterBase Server Hardware
Reducir el número de registros a revisar y a obtener:
Evitar el uso de select (*), es mejor hacer Select campo1, campo2, ...
Utilizar clausula Where para reducir el número de registro a obtener
Para tablas pequeñas y fijas cachearlas en el cliente
Evitar el uso de inner join (2*), siempre que sea posible
Evitar el uso lookup en Delphi, es preferible hacer sql joins
Evitar hacer subconsultas correlativas, es mejor hacer joins (mejora el plan de la consulta), ver ej.

Evitar el uso de Select Count (*):
Determinar si una tabla está vacía en código:
if not MyTable.IsEmpty then begin
DoSomething;
end else begin
raise Exception.Create(NORECORDS);
end;
Determinar si una tabla está vacía en Sql o procedimiento o trigger
RDB$DATABASE es una tabla del sistema que siempre tiene un registro
SELECT 'Table is not empty' FROM RDB$DATABASE
WHERE EXISTS (SELECT 1 FROM SOME_TABLE);
Evitar hacer iteraciones en el cliente:
En el caso de tenerlas que hacerlas:
while not MyTable.Eof do begin
DoSomething;
MyTable.Next;
end;
Copiar varias filas de una tabla a otra:
INSERT INTO DESTINATION_TABLE (DEST_ID, SOURCE_ID, DESCRIPTION )
SELECT GEN_ID(DEST_G, 1), SOURCE_ID, DESCRIPTION
FROM SOURCE WHERE
Para borrar Muchas filas a la vez:
DELETE FROM TABLE WHERE SOME_DATE BETWEEN :StartDate AND :StopDate
Para realizar cálculos utilizar select max, min, avg, sum o funciones udf,
y cuando no sea posible hacer los cálculos en procedimientos almacenados
Evitar hacer procedimientos almacenados, cuyo tiempo de ejecución sea excesivamente largo,
puede ir en decremento de los demás clientes
Uso de commit y rollback:
Es preferible hacer commit y rollback que commit_retaining y rollback_retaining (no terminan la transacción)
Evitar el uso de Rollback

Uso de índices:
Comprobar el uso correcto de los índices
Son útiles cuando se quiere leer pocas filas de datos
Es mejor indexar sobre columnas unique, y no hacer dos veces sobre la misma columna
Hacer índices sobre campos que seán selectivos
En la cláusula where las n primeras columnas deben ser las n primeras columnas del índice a usar
(todas, o las n primeras) en el mismo orden
Crear un índice por cada columna del "where", o sólo uno que se muy selectivo
Índice descendiente -> función Max
Índice ascendiente -> función Min, Select desc from tabla where cod = 100 ;
Para funciones Sum, Avg no se puede aprovechar los índices
Rebalancear índices con alter index xx inactive / active (cuidado con clientes activos)
Interbase's optimizer tratará de evitar un índice que no sea sumamente selectivo,
pero no podrá crear un índice donde no exista.
Evitar el uso de índices:
Select emp_no, first_name, last_name || '' from Employee order by 3, 2(Para nímeros 0 ||)
No son útiles cuando se tienen que leer todos o casi todos los datos,
o no reducen en consideración el número de registros a leer,
es decir el índice es poco selectivo,
sobre todo si el orden del índice no coincide con el orden de almacenamiento.
Un gran número de índices penaliza las inserciones (por tener que ir actualizando
todos los índices por cada inserción)
Ver apartado ordenando los datos
Ordenando los datos:
La manera más rápida de obtener los registros es en el orden de almacenamiento
donde el plan sea (PLAN (NOMBRE_TABLA NATURAL)
Hay dos formas de ordenador un resultado, leyendo los datos en orden usando un
índice o leer todos los datos en el orden que están almacenados y después
hacer la ordenación en memoria. Para un gran volumen de registros suele más
rápido las segunda opción, sin embargo, la pérdida de velocidad de la primera
opción, se puede compensar si reduce apreciablemente el número de registros
a leer al usar el índice. (nota: el movimiento del disco duro (no secuencial),
buscando los registros en orden, es más lento respecto a una lectura secuencial
y después realizar un QuickSort
Uso de like:
Evitar el uso de "where nombre like '%t%'" no aprovecha el uso de índices,
reemplazar si es posible por "where nombre like 't%'"
Evitar el uso de "where nombre like :nombre"
reemplazar por "where nombre starting with :nombre"
Uso de Union:
Reemplazar el uso de Union (elimina duplicados) por Union all , cuando sea posible
Evitar consultas con subconsultas, que tengan comparaciones de columnas con mas de 1 cte.
Select * From EMP_PROJECT Where EMP_NO In
(Select EMP_NO From EMP Where NAME In ('Nelson', 'Young'));
Select * From EMP_PROJECT Where EMP_NO In
(Select EMP_NO From EMP Where (NAME = 'Nelson') OR (NAME = 'Young'))
Solución:
Crear una tabla con las ctes a buscar
Select * From EMP_PROJECT Where EMP_NO In
(SELECT EMP_NO FROM SELECTED_EMPLOYEES;)
Utilizar Union or Union ALL
Select * From EMP_PROJECT Where EMP_NO In
(Select EMP_NO From EMP Where NAME = 'Nelson')
UNION ALL
Select * From EMP_PROJECT Where EMP_NO In
(Select EMP_NO From EMP Where NAME = 'Young')