Non è chiaro a quale db ti riferisci.
Quindi in generale...
Originariamente inviato da sandroacchiardi
ho una tabella con 400mila righe
una query è molto lenta perchè lavora su un campo data che no è indicizzato
la query è del tipo > di
la mia domanda è
essendo le date praticamente tutte diverse perchè mi memorizza anche il secondo, ha un senso indicizzare il campo data?
la domanda non mi è chiarissima, in verità
il "> di" ha senso se questo partiziona in modo efficiente il dataset (altrimenti puoi provare NOT <= di).
Se hai X righe, ma di queste solo X-2 sono "> di", allora un indice non ti serve a nulla (in questo caso in realtà, come detto, faresti il complemento per prendere le 2).
ATTENZIONE questo vale solo se hai metodi "magici" per avere il numero di righe di una tabella, per mysql (ad esempio) ciò vale per myisam ma NON per innodb
esempio
SELECT COUNT(*) FROM tabella WHERE data > qualcosa;
può essere più convenientemente scritta (a seconda dei casi, ossia selettività, db ed engine) in
SELECT (SELECT COUNT(*) FROM tabella) - COUNT(*) FROM tabella WHERE ID <= qualcosa;
In questo esempio il punto dolente è il "count della tabella": con myisam funziona bene e, talvolta, ti consente di fare una query tipo quella che hai messo in tempi estremamente più ridotti
Esempio di conteggio SENZA where su myisam
codice:
mysql> explain select count(*) from connessioni;
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
1 row in set (0.00 sec)
Ecco invece su una tabella innodb
codice:
mysql> explain select count(*) from documenti;
+----+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | documenti | index | NULL | PRIMARY | 4 | NULL | 8331 | Using index |
+----+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.00 sec)
Guarda ora questo esempio
codice:
mysql> explain select count(*) from documenti where anno>2000;
+----+-------------+-----------+-------+---------------+-------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+-------+---------+------+------+--------------------------+
| 1 | SIMPLE | documenti | range | iAnno | iAnno | 5 | NULL | 4165 | Using where; Using index |
+----+-------------+-----------+-------+---------------+-------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
e questo
codice:
mysql> explain select count(*) from documenti where anno<=2000;
+----+-------------+-----------+-------+---------------+-------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+-------+---------+------+------+--------------------------+
| 1 | SIMPLE | documenti | range | iAnno | iAnno | 5 | NULL | 2240 | Using where; Using index |
+----+-------------+-----------+-------+---------------+-------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
La seconda query è il doppio più veloce rispetto alla prima
-------
Sempre con riferimento a situazioni db-specifiche, ricordo che una query RANGE "disattiva" tutti gli altri indici (se ci sono) nei vari altri "filtri".
... where (anno=2000) and (tipo='p') and (peso>20) and (data>qualcosa) significa che hai DUE range filter (peso e data), dei quali UN SOLO indice sarà usato.
attenzione sempre alla massima selettività, altrimenti ti ritrovi con qualcosa di simile ad un fullscan
-------------
Ed infine un suggerimento "generale": in questo caso è generalmente più efficiente memorizzare le date come UNIX_TIMESTAMP (quindi in campi interi).
In questo caso puoi ridurre la dimensione dell'indice, come giustamente hai segnalato, "potando" i secondi e lasciando solo la data