2016-08-17 2 views
4

Я знаю, что этот вопрос задан несколько раз, но я не смог сделать свой запрос достаточно быстрым, прочитав эти ответы.Как правильно увеличить производительность MySQL путем индексирования

В принципе, у меня есть таблица с 400k строк. Раньше у него было более 1,8 м строк, время запроса - более 17 секунд, поэтому у меня есть задание cron, чтобы отключить записи старше 5 дней в этой таблице, чтобы сохранить записи примерно в 400 тыс. Строк, чтобы время запроса было чуть больше 5 сек и 5 секунд все еще медленно. У нас есть еще несколько таблиц, которые содержат более 2 миллионов записей и используют JOIN, поэтому я предпочитаю сначала решить эту таблицу трендов, чтобы получить больше exp, а затем коснуться других, чтобы повысить производительность запросов в более сложных случаях.

Структура данных:

| _id | doctype | subtype | term | user_id | nug_id | source | timestamp | confidence | 
|-----|---------|---------|------|---------|---------|--------|-----------|------------| 
| 123 | post | keyword | games| 1000 | 200  | twitter| 143389203 | 0.| 

Я индексировали term, timestamp, source, confidence.

Обычно мой запрос:

SELECT term, SUM(confidence) AS relevance FROM trends 
WHERE source IN ("twitter", "tumblr", "instagram", "post", "flickr") 
GROUP BY term ORDER BY relevance DESC 

А вот мой результат:

Showing rows 0 - 29 (165032 total, Query took 5.8050 sec) 

Так что я должен делать дальше, чтобы оптимизировать индекс или запрос для повышения производительности. Теперь я могу предвидеть, насколько плохо мое время запроса будет, когда я запрашиваю JOIN.

Add1: Извините, я забыл приложить выход EXPLAIN.

enter image description here

ADD2: Структура таблицы

CREATE TABLE `trends` (
`_id` bigint(20) NOT NULL AUTO_INCREMENT, 
`doctype` varchar(10) DEFAULT NULL, 
`subtype` varchar(20) DEFAULT NULL, 
`term` varchar(200) DEFAULT NULL, 
`user_id` varchar(100) DEFAULT NULL, 
`nug_id` varchar(100) DEFAULT NULL, 
`timestamp` bigint(20) DEFAULT NULL, 
`source` varchar(100) DEFAULT NULL, 
`confidence` float DEFAULT NULL, 
PRIMARY KEY (`_id`), 
KEY `confidence` (`confidence`), 
KEY `give_me_trends` (`user_id`,`source`), 
KEY `term` (`term`,`source`), 
KEY `timestamp` (`timestamp`,`confidence`), 
KEY `source` (`source`) 
) ENGINE=InnoDB AUTO_INCREMENT=95350350 DEFAULT CHARSET=utf8 

Add3:

После того, как создана новая таблица называется test_trends и скопировать данные из trends таблицы, я протестирована с source колонны в виде целого числа , Также я удалил два столбца doctype и subtype, поскольку они не нужны вообще. Запрашивается ниже:

SELECT term, SUM(confidence) AS relevance FROM test_trends 
WHERE source IN (1,2,3,4,5,6,7) 
GROUP BY term ORDER BY relevance DESC 

в 5.4802 сек.

EXPLAIN, как показано ниже:

| id | select_type | table | type | possible_keys | key | key_len | ref | rows |      Extra     | 
|-----|-------------|-------------|--------|-------------------|---------|-----------|--------|--------|----------------------------------------------| 
| 1 | SIMPLE | test_trends | index | source,source_2 | term_2 | 603 | NULL | 354324 | Using where; Using temporary; Using filesort | 

add4:

Моя тестовая структура таблицы:

CREATE TABLE `test_trends` (
`_id` bigint(20) NOT NULL AUTO_INCREMENT, 
`term` varchar(200) DEFAULT NULL, 
`user_id` varchar(100) DEFAULT NULL, 
`nug_id` varchar(100) DEFAULT NULL, 
`timestamp` bigint(20) DEFAULT NULL, 
`source` tinyint(1) DEFAULT NULL, 
`confidence` float DEFAULT NULL, 
PRIMARY KEY (`_id`), 
KEY `confidence` (`confidence`), 
KEY `give_me_trends` (`user_id`,`source`), 
KEY `term` (`term`,`source`), 
KEY `timestamp` (`timestamp`,`confidence`), 
KEY `source` (`source`), 
KEY `term_2` (`term`), 
KEY `source_2` (`source`,`confidence`,`timestamp`) 
) ENGINE=InnoDB AUTO_INCREMENT=95354268 DEFAULT CHARSET=utf8 

Также я индексироваться term, source, confidence, timestamp.

Add5:

+-------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table  | Non_unique | Key_name  | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+-------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| test_trends | 0   | PRIMARY  | 1   | _id   | A   | 379365  | NULL  | NULL |  | BTREE  |   |    | 
+-------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| test_trends | 1   | confidence  | 1   | confidence | A   | 18   | NULL  | NULL | YES | BTREE  |   |    | 
+-------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| test_trends | 1   | give_me_trends | 1   | user_id  | A   | 149   | NULL  | NULL | YES | BTREE  |   |    | 
+-------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| test_trends | 1   | give_me_trends | 2   | source  | A   | 556   | NULL  | NULL | YES | BTREE  |   |    | 
+-------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| test_trends | 1   | term   | 1   | term  | A   | 379365  | NULL  | NULL | YES | BTREE  |   |    | 
+-------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| test_trends | 1   | term   | 2   | source  | A   | 379365  | NULL  | NULL | YES | BTREE  |   |    | 
+-------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| test_trends | 1   | timestamp  | 1   | timestamp | A   | 13548  | NULL  | NULL | YES | BTREE  |   |    | 
+-------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| test_trends | 1   | timestamp  | 2   | confidence | A   | 189682  | NULL  | NULL | YES | BTREE  |   |    | 
+-------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| test_trends | 1   | source   | 1   | source  | A   | 107   | NULL  | NULL | YES | BTREE  |   |    | 
+-------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| test_trends | 1   | term_2   | 1   | term  | A   | 379365  | NULL  | NULL | YES | BTREE  |   |    | 
+-------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| test_trends | 1   | source_2  | 1   | source  | A   | 18   | NULL  | NULL | YES | BTREE  |   |    | 
+-------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| test_trends | 1   | source_2  | 2   | confidence | A   | 189   | NULL  | NULL | YES | BTREE  |   |    | 
+-------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| test_trends | 1   | source_2  | 3   | timestamp | A   | 189682  | NULL  | NULL | YES | BTREE  |   |    | 
+-------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
+0

Вы пытались использовать "EXPLAIN SELECT ...", чтобы выяснить, как MySQL использует свои индексы? Вы должны хотя бы запустить это и изменить свой вопрос, чтобы содержать вывод. – timdev

+1

Просто отредактированный и добавленный вывод EXPLAIN – noob

+0

@Drew, вы имели в виду использование int, а не varchar для некоторых столбцов, таких как 'source', как это:' 1 = "twitter", 2 = "tumble и т. Д." ' – noob

ответ

1

Попробуйте удалить order by и сделать свою сортировку в вашей логики приложения.

Надеюсь, что это может свести к минимуму нагрузку на ваш запрос.

+0

Без 'ORDER BY' определенно быстр. Но я также хочу узнать, можно ли это решить на уровне базы данных или нет. – noob

3

Это будет довольно сложно оптимизировать этот запрос. У вас есть в запросе две вещей, что индекс может помочь:

  • Предикат диапазона (IN()) может быть оказана помощь по индексу на source колонке, но оптимизатор не выберет этот индекс, если совпадающие строки больше чем приблизительно 20% строк в таблице.
  • GROUP BY может помочь индекс в столбце term, чтобы запрос читал таблицу в порядке значений в этом столбце.

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

Вы выполняете полное сканирование индекса вашего term_2, что почти так же дорого, как и сканирование таблицы. Вы можете видеть из EXPLAIN, что он посещает более 354 000 листов этого индекса.

Вы также получаете Using temporary; using filesort

Я бы определил все столбцы NOT NULL, если они не должны быть обнуляемым. Насколько я помню, это помогает избежать примечания Using where.

Вы должны определить индекс покрытия, чтобы убедиться, что в запросе нет необходимости считывать данные вне самой структуры индекса. Создайте индекс в столбцах (term, source, confidence). Убедитесь, что столбец term является первым в этом индексе, порядок остальных двух столбцов не имеет значения.

Убедитесь, что вы увеличили innodb_buffer_pool_size, чтобы удерживать индекс в памяти.

1

Кроме того, что уже упоминалось в других ответах, одна вещь, которая подскакивает мне, заключается в том, что вы ищете ints в столбце varchar, делая столбец недоступным (не используйте индекс).

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

1
  • (Самое важное предложение.) Оба запроса выиграют от «покрытие» INDEX(source, term, confidence) - Запуск с source для фильтрации (WHERE), продолжайте с остальными столбцами, которые используются в запросе. «Покрытие» означает, что запрос будет завершен в индексе, не доходя до данных. Наличие столбцов в этом порядке может устранить таблицу темпа и отсортировать для GROUP BY (но не для ORDER BY).
  • Нормализовать поля (как вы это делали с источником), чтобы уменьшить данные, тем самым, возможно, ускорить процесс. (Обратите внимание, что «key_len» равен 603 в EXPLAIN). Это будет особенно полезно, если индекс слишком велик для кэширования в buffer_pool.
  • Сократите (200), если это практично.
  • Избавиться от избыточных индексов - INDEX(a) не требуется, если у вас есть INDEX(a,b).
  • Является ли какая-то комбинация столбцов "уникальной"?Если это так, мы можем обсудить, как превратить это в PRIMARY KEY.
  • Являются ли данные «только для записи»? То есть вы добавляете новые строки, но никогда не меняете старые строки? Если да, тогда мы можем поговорить о Summary Tables, который может дать вам 10-кратное ускорение. (Это, если оно применяется, даже более важно, чем индекс покрытия.)
  • Использование temp и использование filesort является необходимостью из-за того, что ORDER BY отличается от GROUP BY. Вероятно, нет существенного преимущества при перемещении ORDER BY в код приложения.

My cookbook on indexing.

+1

Сканирование полмиллиона строк занимает время; сводная таблица может уменьшить это число. –

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