Próbowałem rozwiązać następujący problem przez około godzinę i nadal nie dotarłem dalej.
Ok, mam stolik (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 | |
+---------+-------------+------+-----+-------------------+----------------+
Nie przejmuj się indeksami, bawiłem się, próbując znaleźć rozwiązanie. Oto moje zapytanie.
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;
tabela przechowuje informacje o przychodzących żądaniach internetowych, więc jest to dość duża baza danych.
+-----------+
| count(id) |
+-----------+
| 782412 |
+-----------+
zauważ, że nie ma lepszego sposobu na ustawienie klucza podstawowego, ponieważ kolumna id będzie jedynym unikalnym identyfikatorem, jaki mam. Wyżej wymienione zapytanie trwa około 0,6-1,6 sekundy.
Który indeks byłby sprytny? Doszedłem do wniosku, że data indeksowania da mi „złą” liczność, a zatem MySQL go nie użyje. http jest również złym wyborem, ponieważ istnieje tylko około 20 różnych możliwych wartości.
Dzięki za pomoc!
Aktualizacja 1 Dodałem indeks (http, data) zgodnie z sugestią ypercube:
mysql> CREATE INDEX httpDate ON reqs (http, date);
i użył swojego zapytania, ale działało równie źle. Dodano indeks:
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| 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 | |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
i WYJAŚNIĆ
+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+
| 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 |
+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+
Wersja serwera 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)
źródło
http
kolumną zerowalną. Zbadam jutro, jeśli znajdę czas.http NOT NULL
) i kopiując do niej wszystkie dane (oczywiście oprócz wierszy z http NULL).Odpowiedzi:
Mam trzy sugestie
SUGGESTION # 1: Przepisz zapytanie
Powinieneś przepisać zapytanie w następujący sposób
lub
GDZIE nie powinno mieć funkcji po obu stronach znaku równości. Posiadanie daty po lewej stronie znaku równości ułatwia Optymalizatorowi zapytań użycie indeksu przeciwko niemu.
SUGGESTION # 2: Supporting Index
Sugerowałbym również inny indeks
Sugeruję tę kolejność kolumn, ponieważ wszystkie
date
wpisy będą ciągłe w indeksie. Następnie zapytanie po prostu zbierahttp
wartości bez pomijania lukhttp
.SUGESTIA # 3: Większy bufor kluczy (opcjonalnie)
MyISAM używa tylko buforowania indeksu. Ponieważ zapytanie nie powinno dotykać
.MYD
pliku, należy użyć nieco większego bufora kluczy MyISAM.Aby ustawić go na 256M
Następnie ustaw
my.cnf
Ponowne uruchomienie MySQL nie jest wymagane
Spróbuj !!!
źródło
Zmień typ kolumny daty na liczbę całkowitą. Przechowuj datę jako datę uniksową w liczbach całkowitych. Znacznik czasu Jest znacznie większy niż int. Dostaniesz z tego trochę huku.
źródło
INT
iTIMESTAMP
potrzebują 4 bajtów.