2012-06-01 2 views
4

У меня проблемы с выполнением запросов MySQL.Настройка производительности конкретного пользователя MySQL

Таблица (InnoDB):

+--------------------+---------------------+------+-----+-------------------+-------+ 
| Field    | Type    | Null | Key | Default   | Extra | 
+--------------------+---------------------+------+-----+-------------------+-------+ 
| st_resource_id  | varchar(32)   | NO | MUL | NULL    |  | 
| st_sub_resource_id | varchar(32)   | YES |  | NULL    |  | 
| st_title   | varchar(500)  | YES |  | NULL    |  | 
| st_resource_type | varchar(100)  | NO | MUL | NULL    |  | 
| st_site_id   | tinyint(4)   | NO | MUL | NULL    |  | 
| st_time   | timestamp   | NO | MUL | CURRENT_TIMESTAMP |  | 
| st_user_id   | int(10) unsigned | YES |  | NULL    |  | 
| st_full_access  | tinyint(1) unsigned | YES |  | NULL    |  | 
+--------------------+---------------------+------+-----+-------------------+-------+ 

Индексы:

+---------------+------------+------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table   | Non_unique | Key_name   | Seq_in_index | Column_name  | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+---------------+------------+------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+ 
| nr_statistics |   1 | resource_id  |   1 | st_resource_id  | A   |  1546165 |  NULL | NULL |  | BTREE  |   | 
| nr_statistics |   1 | resource_id  |   2 | st_sub_resource_id | A   |  1546165 |  NULL | NULL | YES | BTREE  |   | 
| nr_statistics |   1 | st_time   |   1 | st_time   | A   |  1546165 |  NULL | NULL |  | BTREE  |   | 
| nr_statistics |   1 | st_site_id  |   1 | st_site_id   | A   |   16 |  NULL | NULL |  | BTREE  |   | 
| nr_statistics |   1 | st_resource_type |   1 | st_resource_type | A   |   16 |  10 | NULL |  | BTREE  |   | 
+---------------+------------+------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+ 

Запрос:

SELECT st_resource_id AS docId, count(*) AS cnt 
FROM nr_statistics 
WHERE 
    st_resource_type = 'document' 
    AND st_sub_resource_id = 'text' 
    AND st_time > DATE_SUB(NOW(), INTERVAL 7 DAY) 
    AND st_site_id = 1 
GROUP BY st_resource_id 
ORDER BY cnt DESC 
LIMIT 0, 5; 

план запроса:

+----+-------------+---------------+-------+-------------------------------------+-------------+---------+------+---------+----------------------------------------------+ 
| id | select_type | table   | type | possible_keys      | key   | key_len | ref | rows | Extra          | 
+----+-------------+---------------+-------+-------------------------------------+-------------+---------+------+---------+----------------------------------------------+ 
| 1 | SIMPLE  | nr_statistics | index | st_time,st_site_id,st_resource_type | resource_id | 197  | NULL | 1581044 | Using where; Using temporary; Using filesort | 
+----+-------------+---------------+-------+-------------------------------------+-------------+---------+------+---------+----------------------------------------------+ 

Таблица имеет 1 666 383 строки. Запрос выполняется очень медленно. В списке процессов MySQL я вижу этот запрос в «copy to tmp table phase» в течение длительного времени (> 1 минута). Запрос генерирует тяжелую нагрузку ввода-вывода. Я не могу понять, что делать, чтобы исправить проблему и ускорить выполнение запроса.

Если проблема связана с неправильными индексами, то какие индексы будут правильными?

UPD. Я создал новый композитный индекс:

| nr_statistics |   1 | st_site_id_2  |   1 | st_site_id   | A   |   16 |  NULL | NULL |  | BTREE  |   | 
| nr_statistics |   1 | st_site_id_2  |   2 | st_resource_type | A   |   16 |  NULL | NULL |  | BTREE  |   | 
| nr_statistics |   1 | st_site_id_2  |   3 | st_sub_resource_id | A   |  752018 |  NULL | NULL | YES | BTREE  |   | 
| nr_statistics |   1 | st_site_id_2  |   4 | st_time   | A   |  1504037 |  NULL | NULL |  | BTREE  |   | 
| nr_statistics |   1 | st_site_id_2  |   5 | st_resource_id  | A   |  1504037 |  NULL | NULL |  | BTREE  |   | 

Теперь запрос план является:

+----+-------------+---------------+-------+---------------+--------------+---------+------+-------+-----------------------------------------------------------+ 
| id | select_type | table   | type | possible_keys | key   | key_len | ref | rows | Extra              | 
+----+-------------+---------------+-------+---------------+--------------+---------+------+-------+-----------------------------------------------------------+ 
| 1 | SIMPLE  | nr_statistics | range | st_site_id_2 | st_site_id_2 | 406  | NULL | 21168 | Using where; Using index; Using temporary; Using filesort | 
+----+-------------+---------------+-------+---------------+--------------+---------+------+-------+-----------------------------------------------------------+ 

Запрос в настоящее время работает очень быстро (как 0.0x сек), но я должен заставить используя новый индекс:

SELECT st_resource_id as docId, count(*) AS Cnt 
FROM nr_statistics 
USE INDEX (st_site_id_2) 
WHERE st_resource_type = 'document' 
AND st_sub_resource_id = 'text' 
AND st_time > DATE_SUB(NOW() , INTERVAL 7 DAY) 
AND st_site_id = 1 
GROUP BY st_resource_id 
ORDER BY cnt DESC 
LIMIT 0 , 5; 

Хотя проблема решена (не красивая, но эффективная дорога), у меня все еще есть некоторые открытые вопросы (см. Комментарии).

ответ

2

Создайте составной индекс на (st_site_id, st_resource_type, st_sub_resourse_id, st_time, st_resource_id).

Тем не менее, вы по-прежнему будете иметь temporary и filesort в плане, потому что вы делаете заказ на COUNT(*), который не является индексируемым.

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

+0

Я создал составной индекс, как вы сказали. Но MySQL все еще не использует его. Когда я заставил mysql использовать новый тарифный план изменения индекса (см. Обновление в моем вопросе). Но спектакль прошел отлично! Запрос выполняется через 0.0xxx секунд. Великий thans для этого совета. Почему MySQL не использует новый индекс автоматически? Почему 4 независимых индекса не могут использоваться MySQL? Это почти то же самое, что и один составной? –

+0

@ValeraLeontyev: один составной индекс не совсем такой же, как 4 независимых. 4 индекса не образуют единый диапазон, где находятся все ваши записи. Они могут использоваться для улучшения скорости запроса (с помощью 'index_merge'), но только при условии равенства, и кажется, что это предикат' st_time', который является наиболее избирательным для вашего запроса. – Quassnoi

1

Вы пытались создать составной индекс на st_resource_type, st_resource_id, st_time and st_site_id? Мне кажется, что у вас есть несколько индексов, но большинство из них находятся в одной колонке или, возможно, в двух столбцах. Имея составной индекс с большим количеством необходимых столбцов, он может повысить производительность.

0

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

В вашем конкретном случае это будет:

CREATE INDEX stats_index ON nr_statistics (st_resource_type, st_sub_resource_id, st_time, st_site_id); 

Это должно дать вам очень хороший прирост скорости.

Смежные вопросы