2010-11-15 16 views
5

Si usted tiene una consulta como:SQLite unirse a la optimización

select a.Name, a.Description from a 
inner join b on a.id1 = b.id1 
inner join c on b.id2 = c.id2 
group by a.Name, a.Description 

¿Cuál puede ser las columnas más óptimas para indexar para esta consulta en SQLite si se tiene en cuenta que hay más de 100.000 filas en cada una de las mesas?

La razón por la que pregunto es que no obtengo el rendimiento con la consulta con el grupo por el que esperaría de otro RDBMS (SQL Server) cuando aplico la misma optimización.

¿Tendría razón al pensar que todas las columnas a las que se hace referencia en una sola tabla en una consulta en SQLite deben incluirse en un solo índice compuesto para obtener el mejor rendimiento?

+2

Mi psicópata interno se estremece por el hecho de que tiene una cláusula group by sin ninguna función agregada (s). ¿Qué estás tratando de lograr con el grupo? –

+1

@MyOtherMe: vea mi respuesta a continuación, creo que quiere una distinción de todas las descripciones y nombres a los que se hace referencia en las tablas byc. – MPelletier

+0

Eso es exactamente lo que estoy buscando. – gmn

Respuesta

4

El problema es que espera que SQLite tenga las mismas características de rendimiento que un RDBMS completo. No lo hará. SQLLite no tiene el lujo de llegar a la memoria caché tanto en memoria, tiene que reconstruir la memoria caché cada vez que ejecuta la aplicación, es probable que se limite a establecer el número de núcleos, etc., etc. Compensaciones por usar un RDBMS incrustado sobre uno completo.

En cuanto a las optimizaciones, intente indexar las columnas de búsqueda y probar. Luego intenta crear un índice de cobertura. Asegúrese de probar selects y rutas de código que actualicen la base de datos, usted está acelerando una a expensas de la otra. Encuentre la indexación que le proporcione el mejor equilibrio entre los dos para sus necesidades y vaya con ello.

+0

Gracias por la respuesta, previamente intenté agregar un índice compuesto previamente en a.Id1, a.nombre, a.description y compuesto en b.id1, ​​b.id2 y otro índice en c.id2. Sin embargo, ninguno de estos ayudó con el rendimiento del grupo. Esto es de lo que surgió la pregunta, ya que parece imposible obtener un grupo suficiente por rendimiento en esta situación con SQLite. Supongo que esta es solo una de las limitaciones de tener una base de datos integrada. – gmn

1

Cuidado: no sé nada de las posibles complejidades de SQLite y sus planes de ejecución.

Definitivamente necesita índices en a.id1, b.id1, b.id2 y c.id2. Creo que un índice compuesto (b.id1, b.id2) podría producir un pequeño aumento en el rendimiento. Lo mismo ocurre con (a.id1, a.Name, a.Description).

2

Desde el SQLite query optimization overview:

Al hacer una búsqueda indexada de una fila, el procedimiento habitual es hacer una búsqueda binaria en el índice para encontrar la entrada de índice, a continuación, extraer el ID de fila del índice y el uso que se rowid para hacer una búsqueda binaria en la tabla original. Por lo tanto, una búsqueda indexada típica implica dos búsquedas binarias. Sin embargo, si todas las columnas que se deben obtener de la tabla ya están disponibles en el índice, SQLite utilizará los valores que contiene el índice y nunca buscará la fila de la tabla original. Esto guarda una búsqueda binaria para cada fila y puede hacer que muchas consultas se ejecuten dos veces más rápido.

Para cualquier otro RDBMS, yo diría poner un índice agrupado en b.id1 y c.id2. Para SQLite, es mejor que incluya cualquier columna de byc que quiera buscar en esos índices también.

+0

Existen índices de cobertura en casi todos los RDBMS y tienen el mismo efecto en las búsquedas. El problema es que los índices grandes perjudican el rendimiento de inserción/actualización, por lo que hay que hacer malabares con la compensación entre el rendimiento de la actualización y el rendimiento. – Donnie

+0

Gracias por la respuesta, disculpe mi ignorancia, pero ¿está diciendo que es posible en SQLite crear un índice que incluya columnas de varias tablas, similar a una vista indexada en SQLServer? – gmn

+1

Bueno, no, estaba diciendo que cuando creas un índice en B, no solo crees el índice en B.id sino que también incluyes todas las columnas de datos que necesitas de B en el índice. Esto le ahorrará una búsqueda binaria para esas columnas de datos. En otro DBMS probablemente podría ser aún más rápido al incluir columnas de varias tablas en un índice, pero SQLite no es tan avanzado. – thomaspaulb

0

Puesto que usted no está utilizando las otras mesas para sus columnas de retorno, tal vez esto será más rápido:

SELECT DISTINCT a.Name, a.Description 
FROM a, b, c 
WHERE a.id1 = b.id1 
AND b.id2 = c.id2 

En cuanto a las columnas devueltas, ya que el criterio parece ser sólo de que deben estar vinculados a a a b a c, puede buscar todos los únicos a.Name y a.Description pares.

SELECT DISTINCT a.Name, a.Description 
FROM a 
WHERE a.id1 IN (
SELECT b.id1 
FROM b 
WHERE b.id2 IN (
    SELECT c.id2 
    FROM c 
) 
) 

O, dependiendo de si cada par de a.Name y a.Description es ya único, que debería haber alguna ganancia en averiguar primero los números de identificación a continuación, ir a buscar las otras columnas.

SELECT a.Name, a.Description 
FROM a 
WHERE a.id1 IN (
SELECT DISTINCT a.id1 
FROM a 
WHERE a.id1 IN (
    SELECT b.id1 
    FROM b 
    WHERE b.id2 IN (
    SELECT c.id2 
    FROM c 
    ) 
) 
) 
1

creo índices en a.id1 y b.id2 le daría sobre el mayor beneficio que podría obtener en términos de las uniones. Pero SQLite ofrece EXPLAIN, y puede ayudarle a determinar si hay una eficacia evitable en el plan de ejecución actual.