Проблема производительности MySQL при использовании индексированного столбца datetime

15

Я пытался решить следующую проблему в течение часа и так и не получил дальнейшее развитие.

Хорошо, у меня есть таблица (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 |                |
+---------+-------------+------+-----+-------------------+----------------+

Пожалуйста, не обращайте внимания на индексы, я пытался найти решение. Теперь вот мой запрос.

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;

таблица хранит информацию о входящих веб-запросах, поэтому это довольно большая база данных.

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

обратите внимание, что нет лучшего способа установить первичный ключ, так как столбец id будет единственным уникальным идентификатором, который у меня есть. Вышеупомянутый запрос занимает около 0,6-1,6 секунд для запуска.

Какой индекс будет умным? Я полагал, что дата индексации даст мне «плохую» мощность, и поэтому MySQL не будет ее использовать. http также является плохим выбором, поскольку существует только около 20 различных возможных значений.

Спасибо за помощь!

Обновление 1 Я добавил индекс (http, date), как предложил ypercube:

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

и использовал его запрос, но он выполнялся одинаково плохо. Добавленный индекс:

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

и ОБЪЯСНИТЬ

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

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)
Робин Хеллер
источник
Можете ли вы также добавить версию mysql и какой движок таблицы? (myisam или innodb)
ypercubeᵀᴹ
MyISAM и 5.1.73 - все подробности теперь в посте.
Робин Хеллер
Боюсь, это может быть связано с тем, что httpколонка обнуляется. Я буду расследовать завтра, если найду время.
ypercubeᵀᴹ
Боюсь, это может быть связано с тем, что столбец http обнуляется. Я буду расследовать завтра, если найду время. Вы можете проверить, создав идентичную таблицу (кроме как с помощью http NOT NULL) и скопировав в нее все данные (кроме строк с http NULL, конечно.)
ypercubeᵀᴹ
Если изменить его на NOT NULL (что вполне возможно, я не возражал против этого при создании таблицы), то производительность выросла до ~ 1 с - 1,6 с (мой запрос). Спасибо за ваши усилия до сих пор.
Робин Хеллер

Ответы:

10

У меня есть три предложения

ПРЕДЛОЖЕНИЕ № 1: Перепишите запрос

Вы должны переписать запрос следующим образом

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

или

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;

ГДЕ не должно иметь функции с обеих сторон знака равенства. Наличие даты в левой части знака равенства позволяет оптимизатору запросов использовать индекс против него.

ПРЕДЛОЖЕНИЕ № 2: Индекс поддержки

Я бы также предложил другой индекс

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

Я предлагаю этот порядок столбцов, потому dateчто все записи будут смежными в индексе. Затем запрос просто собирает httpзначения без пропусков в http.

ПРЕДЛОЖЕНИЕ № 3: больший ключевой буфер (необязательно)

MyISAM использует только кэширование индекса. Так как запрос не должен касаться .MYDфайла, вы должны использовать немного больший MyISAM Key Buffer.

Чтобы установить его на 256M

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

Затем установите его в my.cnf

[mysqld]
key_buffer_size = 256M

Перезапуск MySQL не требуется

Попробуйте!

RolandoMySQLDBA
источник
Я попробовал вопросы, которые вы мне дали. # 1 выступил примерно так же хорошо, как другое предложение или мое собственное, второе на самом деле хуже. То же самое для индекса поддержки - падение производительности примерно на 75 процентов. Я собираюсь попробовать больший ключевой буфер сейчас, спасибо в любом случае!
Робин Хеллер
Я принял ваш ответ, хотя это не решило проблему, с большим буфером ключей, однако он работал несколько лучше. Закрытие это как лучшее решение из всех. Спасибо!
Робин Хеллер
Чтобы Предложение № 2 работало, может потребоваться добавить в запрос «USE INDEX» или «FORCE INDEX», по крайней мере, это то, что мне нужно было сделать, чтобы ускорить мой запрос после создания такого индекса.
Johano Fierra
-2

Измените тип столбца даты на целое число. Сохраните дату как дату Unix в целом числе. Отметка времени намного больше, чем int. Вы получите от этого какой-то удар.

apachebeard
источник
2
Ты издеваешься? И то INTи другое TIMESTAMPнужно 4 байта.
ypercubeᵀᴹ
2
Не говоря уже о том, что вы теряете все функции datetime, когда вы храните даты или метки времени как целые числа.
ypercubeᵀᴹ