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.