Problema di prestazioni di MySQL tramite la colonna indicizzata datetime


14

Ho provato a risolvere il seguente problema per circa un'ora e ancora non ci sono riuscito.

Ok, ho un tavolo (MyISAM):

+---------+-------------+------+-----+-------------------+----------------+
| Field   | Type        | Null | Key | Default           | Extra          |
+---------+-------------+------+-----+-------------------+----------------+
| id      | int(11)     | NO   | PRI | NULL              | auto_increment |
| http    | smallint(3) | YES  | MUL | 200               |                |
| elapsed | float(6,3)  | NO   |     | NULL              |                |
| cached  | tinyint(1)  | YES  |     | NULL              |                |
| ip      | int(11)     | NO   |     | NULL              |                |
| date    | timestamp   | NO   | MUL | CURRENT_TIMESTAMP |                |
+---------+-------------+------+-----+-------------------+----------------+

Per favore, non preoccuparti degli indici, ho provato a cercare una soluzione. Ora, ecco la mia domanda.

SELECT http,
COUNT( http )  AS count 
FROM reqs
WHERE DATE(date) >= cast(date_sub(date(NOW()),interval 24 hour) as datetime)
GROUP BY http
ORDER BY count;

la tabella memorizza informazioni sulle richieste Web in entrata, quindi è un database piuttosto grande.

+-----------+
| count(id) |
+-----------+
|    782412 |
+-----------+

si noti che non esiste un modo migliore per impostare una chiave primaria poiché la colonna ID sarà l'unico identificatore univoco che ho. L'esecuzione della query sopra menzionata richiede circa 0,6-1,6 secondi.

Quale indice sarebbe intelligente? Ho pensato che la data di indicizzazione mi avrebbe dato una "cattiva" cardinalità e quindi MySQL non la userà. Anche http è una cattiva scelta in quanto vi sono solo circa 20 diversi possibili valori.

Grazie per il tuo aiuto!

Aggiornamento 1 Ho aggiunto un indice su (http, data) come suggerito da ypercube:

mysql> CREATE INDEX httpDate ON reqs (http, date);

e ha usato la sua query, ma ha funzionato ugualmente male. L'indice aggiunto:

+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| reqs  |          0 | PRIMARY  |            1 | id          | A         |      798869 |     NULL | NULL   |      | BTREE      |         |
| reqs  |          1 | httpDate |            1 | http        | A         |          19 |     NULL | NULL   | YES  | BTREE      |         |
| reqs  |          1 | httpDate |            2 | date        | A         |       99858 |     NULL | NULL   |      | BTREE      |         |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

e SPIEGARE

+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+
| id | select_type        | table | type  | possible_keys | key      | key_len | ref  | rows  | Extra                                                     |
+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+
|  1 | PRIMARY            | r     | range | NULL          | httpDate | 3       | NULL |    20 | Using index for group-by; Using temporary; Using filesort |
|  2 | DEPENDENT SUBQUERY | ri    | ref   | httpDate      | httpDate | 3       | func | 41768 | Using where; Using index                                  |
+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+

Versione del server MySQL:

mysql> SHOW VARIABLES LIKE "%version%";
+-------------------------+---------------------+
| Variable_name           | Value               |
+-------------------------+---------------------+
| protocol_version        | 10                  |
| version                 | 5.1.73              |
| version_comment         | Source distribution |
| version_compile_machine | x86_64              |
| version_compile_os      | redhat-linux-gnu    |
+-------------------------+---------------------+
5 rows in set (0.00 sec)

Puoi anche aggiungere la versione mysql e qual è il motore della tabella? (myisam o innodb)
— ypercubeᵀᴹ

MyISAM e 5.1.73 - tutti i dettagli ora nel post.
— Robin Heller,

Temo che potrebbe avere a che fare con la httpcolonna che è nullable. Domani indagherò, se trovo il tempo.
— ypercubeᵀᴹ

Temo che potrebbe avere a che fare con la colonna http nulla. Domani indagherò, se trovo il tempo. Puoi testare creando una tabella identica (tranne con http NOT NULL) e copiando tutti i dati su di essa (tranne le righe con http NULL ovviamente.)
— ypercubeᵀᴹ

Modificandolo in NOT NULL (il che è del tutto possibile, non mi dispiaceva molto durante la creazione della tabella) ha aumentato le prestazioni a circa ~ 1s - 1.6s per la query (la mia query). Grazie per il tuo impegno fino ad ora.
— Robin Heller,

Risposte:


10

Ho tre suggerimenti

SUGGERIMENTO # 1: riscrivere la query

È necessario riscrivere la query come segue

SELECT http,
COUNT( http )  AS count 
FROM reqs
WHERE date >= ( DATE(NOW() - INTERVAL 1 DAY) + INTERVAL 0 SECOND )
GROUP BY http
ORDER BY count;

o

SELECT * FROM
(
    SELECT http,
    COUNT( http )  AS count 
    FROM reqs
    WHERE date >= ( DATE(NOW() - INTERVAL 1 DAY) + INTERVAL 0 SECOND )
    GROUP BY http
) A ORDER BY count;

WHERE non dovrebbe avere una funzione su entrambi i lati del segno di uguale. La data sul lato sinistro del segno di uguale rende più semplice l'utilizzo di un indice per lo Strumento per ottimizzare le query.

SUGGERIMENTO # 2: indice di supporto

Vorrei anche suggerire un indice diverso

ALTER TABLE reqs ADD INDEX date_http_ndx (date,http); -- not (http,date) 

Suggerisco questo ordine di colonne perché le datevoci sarebbero tutte contigue nell'indice. Quindi, la query raccoglie semplicemente i httpvalori senza saltare le lacune http.

SUGGERIMENTO # 3: buffer chiave più grande (opzionale)

MyISAM utilizza solo la cache dell'indice. Poiché la query non deve toccare il .MYDfile, è necessario utilizzare un buffer delle chiavi MyISAM leggermente più grande.

Per impostarlo su 256M

SET @newsize = 1024 * 1024 * 256;
SET GLOBAL key_buffer_size = @newsize;

Quindi, impostalo my.cnf

[mysqld]
key_buffer_size = 256M

Riavvio di MySQL non richiesto

Provaci !!!


Ho provato le domande che mi hai dato. Il numero 1 si è comportato bene come l'altro o il mio suggerimento, il secondo in realtà è andato peggio. Stessa cosa per l'Indice di supporto: ridurre le prestazioni di circa il 75 percento. Ora proverò il buffer di chiavi più grande, grazie comunque!
— Robin Heller,

Ho accettato la tua risposta, anche se non ha risolto il problema, con un buffer di chiavi più grande, ma ha funzionato in qualche modo meglio. Chiudendolo perché è la migliore soluzione di tutti. Grazie!
— Robin Heller,

Affinché il Suggerimento n. 2 funzioni, potrebbe essere necessario aggiungere "USE INDEX" o "FORCE INDEX" alla query, almeno questo è quello che dovevo fare per accelerare la mia query dopo aver creato un indice del genere.
— Johano Fierra,

-2

Cambia il tipo di colonna della data in un numero intero. Memorizza la data come data Unix in numero intero. Il timestamp è molto più grande di un int. Ne trarrai un bel colpo.


2
Stai scherzando? Entrambi INTe hanno TIMESTAMPbisogno di 4 byte.
— ypercubeᵀᴹ

2
Per non parlare del fatto che si perdono tutte le funzioni di data e ora quando si memorizzano date o timestamp come numeri interi.
— ypercubeᵀᴹ
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.