2010-04-17 58 views
7

Tengo dos posibles consultas, ambas dando el conjunto de resultados que quiero.¿Por qué SQLite tarda tanto tiempo en recuperar los datos?

Querer una toma alrededor de 30ms, pero 150ms para recuperar los datos de la base de datos.

SELECT 
    id 
FROM 
    featurevalues as featval3 
WHERE 
    featval3.feature IN (?,?,?,?) 
AND 
    EXISTS 
    (
     SELECT 
      1 
     FROM 
      product_to_value, 
      product_to_value as prod2, 
      features, 
      featurevalues 
     WHERE 
      product_to_value.feature = features.int 
     AND 
      product_to_value.value = featurevalues.id 
     AND 
      features.id = ? 
     AND 
      featurevalues.id IN (?,?) 
     AND 
      product_to_value.product = prod2.product 
     AND 
      prod2.value = featval3.id 
    ) 

de consultas sobre dos tomas 3ms -este es el que por lo tanto preferible, pero también toma 170 ms para recuperar los datos.

SELECT 
    (
     SELECT 
      prod2.value 
     FROM 
      product_to_value, 
      product_to_value as prod2, 
      features, 
      featurevalues 
     WHERE 
      product_to_value.feature = features.int 
     AND 
      product_to_value.value = featurevalues.id 
     AND 
      features.id = ? 
     AND 
      featurevalues.id IN (?,?) 
     AND 
      product_to_value.product = prod2.product 
     AND 
      prod2.value = featval3.id 
    ) as id 
FROM 
    featurevalues as featval3 
WHERE 
    featval3.feature IN (?,?,?,?) 

El 170ms parece estar relacionado con el número de filas de la tabla featval3. Después de usar un índice en featval3.feature IN (?,?,?,?), 151 elementos "permanecen" en featval3.

¿Hay algo obvio que me falta con respecto a la lenta recuperación? Hasta donde sé, todo está indexado correctamente. Estoy confundido porque la segunda consulta solo tarda 3 meses en ejecutarse.

actualización

Esto es lo que me pasa cuando estoy corriendo un explique en la segunda consulta:

0 Trace 0 0 0 00 
1 Variable 4 1 4 00 
2 Goto 0 88 0 00 
3 OpenRead 5 6883 0 00 
4 If 6 16 0 00 
5 Integer 1 6 0 00 
6 OpenEphemeral 7 1 0 00 
7 Null 0 8 0 00 
8 MakeRecord 1 1 8 00 
9 IdxInsert 7 8 0 00 
10 MakeRecord 2 1 8 00 
11 IdxInsert 7 8 0 00 
12 MakeRecord 3 1 8 00 
13 IdxInsert 7 8 0 00 
14 MakeRecord 4 1 8 00 
15 IdxInsert 7 8 0 00 
16 Rewind 7 86 0 00 
17 Column 7 0 5 00 
18 IsNull 5 85 0 00 
19 Affinity 5 1 0 00 
20 SeekGe 5 85 5 00 
21 IdxGE 5 85 5 01 
22 Null 0 10 0 00 
23 Integer 1 11 0 00 
24 MustBeInt 11 0 0 00 
25 IfZero 11 82 0 00 
26 Variable 1 12 3 00 
27 OpenRead 2 25 0 00 
28 OpenRead 8 7005 0 00 
29 OpenRead 9 26 0 00 
30 OpenRead 10 6732 0 00 
31 OpenRead 11 6766 0 00 
32 Column 5 1 15 00 
33 IsNull 15 77 0 00 
34 Affinity 15 1 0 00 
35 SeekGe 8 77 15 00 
36 IdxGE 8 77 15 01 
37 IdxRowid 8 8 0 00 
38 Seek 2 8 0 00 
39 Column 2 0 16 00 
40 IsNull 16 76 0 00 
41 Affinity 16 1 0 00 
42 SeekGe 9 76 16 00 
43 IdxGE 9 76 16 01 
44 Column 9 1 17 00 
45 IsNull 17 75 0 00 
46 SCopy 12 18 0 00 
47 IsNull 18 75 0 00 
48 Affinity 17 2 0 00 
49 SeekGe 10 75 17 00 
50 IdxGE 10 75 17 01 
51 If 20 59 0 00 
52 Integer 1 20 0 00 
53 OpenEphemeral 13 1 0 00 
54 Null 0 21 0 00 
55 MakeRecord 13 1 21 00 
56 IdxInsert 13 21 0 00 
57 MakeRecord 14 1 21 00 
58 IdxInsert 13 21 0 00 
59 Rewind 13 74 0 00 
60 Column 13 0 19 00 
61 IsNull 19 73 0 00 
62 Affinity 19 1 0 00 
63 SeekGe 11 73 19 00 
64 IdxGE 11 73 19 01 
65 Column 9 2 21 00 
66 Column 11 0 7 00 
67 Ne 7 72 21 6a 
68 Column 8 0 22 00 
69 Move 22 10 1 00 
70 AddImm 11 -1 0 00 
71 IfZero 11 77 0 00 
72 Next 11 64 0 00 
73 Next 13 60 0 00 
74 Next 10 50 0 00 
75 Next 9 43 0 00 
76 Next 8 36 0 00 
77 Close 2 0 0 00 
78 Close 8 0 0 00 
79 Close 9 0 0 00 
80 Close 10 0 0 00 
81 Close 11 0 0 00 
82 SCopy 10 9 0 00 
83 ResultRow 9 1 0 00 
84 Next 5 21 0 00 
85 Next 7 17 0 00 
86 Close 5 0 0 00 
87 Halt 0 0 0 00 
88 Transaction 0 0 0 00 
89 VerifyCookie 0 319 0 00 
90 TableLock 0 14 0 00 
91 TableLock 0 25 0 00 
92 TableLock 0 11 0 00 
93 Goto 0 3 0 00 

No está seguro de lo que significa sin embargo.

+0

¿Cómo está obteniendo los datos? – dan04

+0

Usando PHP: 'while ($ row = $ statement-> fetch (PDO :: FETCH_OBJ))' – SQLighter

Respuesta

4

No estoy seguro acerca de sqlite, pero la mayoría de las bases de datos no calculan el conjunto de resultados completo de inmediato cuando ejecuta una consulta. Compilan y optimizan la consulta, luego comienzan a ejecutarla buscando las primeras filas.

Más o menos cómo es rápido abrir un archivo grande, pero lleva mucho tiempo leer todo el contenido.

-1

Utilice Begin Transaction y End Transaction en cualquier momento que escriba una consulta sql. Esto se explica aquí, además de gran cantidad de otra información útil:

SQLite Optimization FAQ

Puede comprobar los detalles de indexación en donde cláusula aquí:

SQLite Query Optimizer Overview

+0

Si no usa BEGIN/END TRANSACTION, cada instrucción obtiene su propia transacción. El uso de transacciones explícitas mejora la eficiencia con múltiples declaraciones, pero el OP solo está ejecutando una. – dan04

+0

No estoy escribiendo. – SQLighter

3

Probablemente debería utilizar JOINs aquí y su el uso de subconsultas correlacionadas bien puede ralentizar las cosas. Si bien es cierto que a menudo el optimizador puede ejecutar una unión cruzada con una cláusula where como si fuera una unión, y también puede ejecutar subconsultas correlacionadas como combinaciones, no contaría con que SQLite pueda hacer esto en todos los casos. La reescritura de la consulta con juntas Creo que esto da:

SELECT DISTINCT prod2.value AS id 
FROM product_to_value 
JOIN features ON product_to_value.feature = features.int 
JOIN product_to_value as prod2 ON product_to_value.product = prod2.product 
JOIN featurevalues as featval3 ON prod2.value = featval3.id 
JOIN featurevalues ON product_to_value.value = featurevalues.id 
WHERE features.id = ? 
AND featurevalues.id IN (?,?) 
AND featval3.feature IN (?,?,?,?) 

Intenta lo siguiente y es más rápido (y todavía da el resultado correcto).

+0

SQLite traduce JOINs a la cláusula WHERE. Estoy bastante seguro de que la consulta hace lo que tiene que hacer. – SQLighter

+0

El problema que recibo con la consulta que ha publicado es que devuelve valores duplicados. Podría resolver esto con DISTINCT o una tabla temporal, pero esto sería muy lento, especialmente cuando tiene que lidiar con un gran conjunto de resultados. Por lo tanto, pensé que podría ir por ahí usando una subconsulta en cada fila de un conjunto de resultados más pequeño de featval3.IN (?,?,?,?). – SQLighter

+1

@Derk: OK, me lo perdí. Era difícil entender lo que hacía su consulta. He agregado DISTINCT. Las subconsultas correlacionadas pueden ser lentas porque es posible que necesite varios escaneos sobre las tablas/índices en lugar de solo un escaneo. –

Cuestiones relacionadas