MySQL-Leistungsproblem bei Verwendung einer indizierten datetime-Spalte


14

Ich habe versucht, das folgende Problem etwa eine Stunde lang zu lösen und bin trotzdem nicht weitergekommen.

Okay, ich habe einen Tisch (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 |                |
+---------+-------------+------+-----+-------------------+----------------+

Bitte beachten Sie die Indizes, ich habe versucht, eine Lösung zu finden. Hier ist meine Frage.

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;

Die Tabelle speichert Informationen über eingehende Webanfragen, sodass es sich um eine ziemlich große Datenbank handelt.

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

Beachten Sie, dass es keine bessere Möglichkeit gibt, einen Primärschlüssel festzulegen, da die ID- Spalte die einzige eindeutige Kennung ist, die ich habe. Die oben genannte Abfrage dauert ca. 0,6-1,6 Sekunden.

Welcher Index wäre schlau? Ich stellte dar , dass die Indizierung Datum gibt mir „schlecht“ Mächtigkeit und damit MySQL wird es nicht verwenden. http ist auch eine schlechte Wahl, da es nur ungefähr 20 verschiedene mögliche Werte gibt.

Danke für deine Hilfe!

Update 1 Ich habe einen Index für (http, Datum) hinzugefügt, wie von ypercube vorgeschlagen:

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

und verwendete seine Abfrage, aber es lief genauso schlecht. Der hinzugefügte Index:

+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| 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      |         |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

und die EXPLAIN

+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+
| 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                                  |
+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+

MySQL Server Version:

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)

Können Sie auch die MySQL-Version hinzufügen und was ist die Engine der Tabelle? (myisam oder innodb)
ypercubeᵀᴹ

MyISAM und 5.1.73 - alle Details jetzt in der Post.
Robin Heller

Ich fürchte, es hat möglicherweise damit zu tun, dass die httpSpalte nullwertfähig ist. Ich werde morgen nachforschen, ob ich Zeit finde.
Ypercubeᵀᴹ

Ich befürchte, es könnte damit zu tun haben, dass die http-Spalte nullbar ist. Ich werde morgen nachforschen, ob ich Zeit finde. Sie können testen, indem Sie eine identische Tabelle erstellen (außer mit http NOT NULL) und alle Daten darauf kopieren (außer natürlich die Zeilen mit http NULL.)
ypercubeᵀᴹ 10.08.14

Durch Ändern in NOT NULL (was durchaus möglich ist, es hat mir beim Erstellen der Tabelle nichts ausgemacht) wurde die Leistung für die Abfrage (meine Abfrage) auf etwa ~ 1s - 1,6s erhöht. Vielen Dank für Ihre Bemühungen bis jetzt.
Robin Heller

Antworten:


10

Ich habe drei Vorschläge

VORSCHLAG 1: Schreiben Sie die Abfrage neu

Sie sollten die Abfrage wie folgt umschreiben

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

oder

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;

Das WHERE sollte nicht auf beiden Seiten des Gleichheitszeichens eine Funktion haben. Das Datum auf der linken Seite des Gleichheitszeichens erleichtert es dem Abfrageoptimierer, einen Index dafür zu verwenden.

VORSCHLAG 2: Unterstützender Index

Ich würde auch einen anderen Index vorschlagen

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

Ich schlage diese Reihenfolge der Spalten vor, da datealle Einträge im Index zusammenhängend wären. Die Abfrage sammelt dann einfach httpWerte, ohne Lücken zu überspringen http.

VORSCHLAG 3: Größerer Schlüsselpuffer (optional)

MyISAM verwendet nur Index-Caching. Da die Abfrage die .MYDDatei nicht berühren sollte , sollten Sie einen etwas größeren MyISAM-Schlüsselpuffer verwenden.

Um es auf 256M zu setzen

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

Dann setzen Sie es ein my.cnf

[mysqld]
key_buffer_size = 256M

Neustart von MySQL nicht erforderlich

Versuche es !!!


Ich habe die Fragen ausprobiert, die du mir gegeben hast. Nr. 1 schnitt ungefähr so ​​gut ab wie der andere Vorschlag oder mein eigener, der zweite schnitt sogar schlechter ab. Dasselbe gilt für den Supporting Index - die Performance sinkt um 75 Prozent. Ich werde jetzt den größeren Schlüsselpuffer ausprobieren, trotzdem danke!
Robin Heller

Ich habe Ihre Antwort akzeptiert, obwohl sie das Problem nicht behoben hat. Mit einem größeren Schlüsselpuffer lief sie jedoch etwas besser. Dies zu schließen, ist die beste Lösung überhaupt. Vielen Dank!
Robin Heller

Damit Vorschlag Nr. 2 funktioniert, muss der Abfrage möglicherweise "USE INDEX" oder "FORCE INDEX" hinzugefügt werden. Dies musste ich zumindest tun, um meine Abfrage nach dem Erstellen eines solchen Index zu beschleunigen.
Johano Fierra

-2

Ändern Sie den Datenspaltentyp in eine Ganzzahl. Speichern Sie das Datum als Unix-Datum in Ganzzahl. Timestamp Ist viel größer als ein Int. Sie würden etwas Knall davon bekommen.


2
Machst du Witze? Beide INTund TIMESTAMPbenötigen 4 Bytes.
ypercubeᵀᴹ

2
Ganz zu schweigen davon, dass Sie alle Datums- und Uhrzeitfunktionen verlieren, wenn Sie Datums- oder Zeitstempel als Ganzzahlen speichern.
ypercubeᵀᴹ
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.