Подзапросы и Кэш MySQL для таблицы строк 18M+
поскольку это мой первый пост, кажется, я могу опубликовать только 1 ссылку, поэтому я перечислил сайты, на которые я ссылаюсь, внизу. В двух словах моя цель - сделать так, чтобы база данных возвращала результаты быстрее, я попытался включить как можно больше соответствующей информации, чтобы помочь сформулировать вопросы в нижней части сообщения.
Информация О Машине
8 processors
model name : Intel(R) Xeon(R) CPU E5440 @ 2.83GHz
cache size : 6144 KB
cpu cores : 4
top - 17:11:48 up 35 days, 22:22, 10 users, load average: 1.35, 4.89, 7.80
Tasks: 329 total, 1 running, 328 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.0%us, 0.0%sy, 0.0%ni, 87.4%id, 12.5%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 8173980k total, 5374348k used, 2799632k free, 30148k buffers
Swap: 16777208k total, 6385312k used, 10391896k free, 2615836k cached
однако мы смотрим на перемещение установки mysql на другой компьютер в кластере, который имеет 256 ГБ ОЗУ
Таблица Info
моя таблица MySQL выглядит как
CREATE TABLE ClusterMatches
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
cluster_index INT,
matches LONGTEXT,
tfidf FLOAT,
INDEX(cluster_index)
);
это примерно 18М строк 1М уникальная cluster_index и 6К уникальных игр. Sql-запрос, который я генерирую в PHP, выглядит так.
SQL query
$sql_query="SELECT `matches`,sum(`tfidf`) FROM
(SELECT * FROM Test2_ClusterMatches WHERE `cluster_index` in (".$clusters."))
AS result GROUP BY `matches` ORDER BY sum(`tfidf`) DESC LIMIT 0, 10;";
где $cluster содержит строку примерно из 3000 разделенных запятыми cluster_index. Этот запрос использует приблизительно 50,000 строк и занимает приблизительно 15s для выполнить, когда тот же запрос выполняется снова, для запуска требуется примерно 1s.
использование
- содержимое таблицы можно считать статическим.
- низкое количество одновременных пользователей
- запрос выше в настоящее время является единственным запросом, который будет выполняться в таблице
подзапрос
на основе этого сообщения [stackoverflow: Cache / Re-Use a Subquery in MySQL][1] и улучшение времени запроса Я считаю, что мой подзапрос может быть индексирован.
mysql> EXPLAIN EXTENDED SELECT `matches`,sum(`tfidf`) FROM
(SELECT * FROM ClusterMatches WHERE `cluster_index` in (1,2,...,3000)
AS result GROUP BY `matches` ORDER BY sum(`tfidf`) ASC LIMIT 0, 10;
+----+-------------+----------------------+-------+---------------+---------------+---------+------+-------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------------+-------+---------------+---------------+---------+------+-------+---------------------------------+
| 1 | PRIMARY | derived2 | ALL | NULL | NULL | NULL | NULL | 48528 | Using temporary; Using filesort |
| 2 | DERIVED | ClusterMatches | range | cluster_index | cluster_index | 5 | NULL | 53689 | Using where |
+----+-------------+----------------------+-------+---------------+---------------+---------+------+-------+---------------------------------+
согласно этой старой статье [оптимизация MySQL: запросы и индексы][2] в дополнительной информации - плохие, чтобы увидеть здесь "использование временного" и "использование filesort"
Информация О Конфигурации MySQL
кэш запросов доступен, но эффективно отключен, поскольку размер в настоящее время установлен на ноль
mysqladmin variables;
+---------------------------------+----------------------+
| Variable_name | Value |
+---------------------------------+----------------------+
| bdb_cache_size | 8384512 |
| binlog_cache_size | 32768 |
| expire_logs_days | 0 |
| have_query_cache | YES |
| flush | OFF |
| flush_time | 0 |
| innodb_additional_mem_pool_size | 1048576 |
| innodb_autoextend_increment | 8 |
| innodb_buffer_pool_awe_mem_mb | 0 |
| innodb_buffer_pool_size | 8388608 |
| join_buffer_size | 131072 |
| key_buffer_size | 8384512 |
| key_cache_age_threshold | 300 |
| key_cache_block_size | 1024 |
| key_cache_division_limit | 100 |
| max_binlog_cache_size | 18446744073709547520 |
| sort_buffer_size | 2097144 |
| table_cache | 64 |
| thread_cache_size | 0 |
| query_cache_limit | 1048576 |
| query_cache_min_res_unit | 4096 |
| query_cache_size | 0 |
| query_cache_type | ON |
| query_cache_wlock_invalidate | OFF |
| read_rnd_buffer_size | 262144 |
+---------------------------------+----------------------+
на основе этой статьи о [MySQL Database Performance turning] [3] я считаю, что значения, которые мне нужно настроить, являются
- table_cache
- key_buffer
- sort_buffer
- read_buffer_size
- record_rnd_buffer (для групп и порядка по условиям)
области, определенные для улучшения - MySQL query tweaks
- изменение типа данных для соответствий индексу, который является int, указывающим на другую таблицу [MySQL действительно будет использовать динамический формат строки, если он содержит поля переменной длины, такие как TEXT или BLOB, что в данном случае означает, что сортировка должна выполняться на диске. Решение состоит не в том, чтобы избегать этих типов данных, а в том, чтобы разделить такие поля на связанную таблицу.][4]
- индексирование нового поля match_index так, чтобы группа по
matches
происходит быстрее, на основе оператора ["вы, вероятно, должны создавать индексы для любого поля, на котором вы выбираете, группируете, упорядочиваете или присоединение."][5]
инструменты
для настройки выполнения я планирую использовать
- [Explain][6] ссылка на [выходной формат][7]
- [ab - Apache HTTP server инструмент бенчмаркинга] [8]
- [профилирование][9] С [данные журнала][10]
Будущий Размер Базы Данных
цель состоит в том, чтобы построить систему, которая может иметь 1M уникальных значений cluster_index 1M уникальных значений соответствия, прибл 3,000,000,000 строк таблицы со временем ответа на запрос около 0,5 С (при необходимости мы можем добавить больше ОЗУ и распределить базу данных по кластеру)
вопросы
- я думаю, что мы хотим сохранить весь набор записей в ОЗУ, чтобы запрос не касался диска, если мы сохраняем всю базу данных в кэше MySQL, это устраняет необходимость в memcachedb?
- пытается сохранить всю базу данных в кэше MySQL плохой стратегией, как он не предназначен, чтобы быть настойчивым? Было бы что-то вроде memcachedb или redis лучшим подходом, если да, то почему?
- временная таблица "результат", которая создается запросом, автоматически уничтожается по завершении запроса?
- должны ли мы переключиться с Innodb на MyISAM [как хорошо для чтения тяжелых данных, где InnoDB хорош для записи тяжелых] [11]?
- мой кэш не отображается как ноль в моей [конфигурации кэша запросов][12], Почему запрос в настоящее время происходит быстрее, когда я запускаю его во второй раз?
- могу ли я реструктурировать свой запрос, чтобы исключить" использование временного "и" использование filesort", должен ли я использовать соединение вместо подзапроса?
- как просмотреть размер MySQL [кэш данных][13]?
- какие размеры для значений table_cache, key_buffer, sort_buffer, read_buffer_size, record_rnd_buffer вы бы предложили в качестве стартового смысл?
ссылки
- 1: stackoverflow.com/questions/658937/cache-re-use-a-subquery-in-mysql
- 2: databasejournal.com/features/mysql/article.php/10897_1382791_4/Optimizing-MySQL-Queries-and-Indexes.htm
- 3: debianhelp.co.uk/mysqlperformance.htm
- 4: 20bits.com/articles/10-tips-for-optimizing-mysql-queries-that-dont-suck/
- 5: 20bits.com/articles/10-tips-for-optimizing-mysql-queries-that-dont-suck/
- 6: dev.mysql.com/doc/refman/5.0/en/explain.html
- 7: dev.mysql.com/doc/refman/5.0/en/explain-output.html
- 8: httpd.apache.org/docs/2.2/programs/ab.html
- 9: mtop.sourceforge.net/
- 10: dev.mysql.com/doc/refman/5.0/en/slow-query-log.html
- 11: 20bits.com/articles/10-tips-for-optimizing-mysql-queries-that-dont-suck/
- 12: dev.mysql.com/doc/refman/5.0/en/query-cache-configuration.html
- 13: dev.mysql.com/tech-resources/articles/mysql-query-cache.html
1 ответов
смена стола
на основе рекомендаций в этом посте на как выбрать индексы для заказа и группировать по запросам таблица теперь выглядит так
CREATE TABLE ClusterMatches
(
cluster_index INT UNSIGNED,
match_index INT UNSIGNED,
id INT NOT NULL AUTO_INCREMENT,
tfidf FLOAT,
PRIMARY KEY (match_index,cluster_index,id,tfidf)
);
CREATE TABLE MatchLookup
(
match_index INT UNSIGNED NOT NULL PRIMARY KEY,
image_match TINYTEXT
);
Исключения Подзапрос
запрос без сортировки результатов по сумме(tfidf) выглядит
SELECT match_index, SUM(tfidf) FROM ClusterMatches
WHERE cluster_index in (1,2,3 ... 3000) GROUP BY match_index LIMIT 10;
что исключает использование временных и использование filesort
explain extended SELECT match_index, SUM(tfidf) FROM ClusterMatches
WHERE cluster_index in (1,2,3 ... 3000) GROUP BY match_index LIMIT 10;
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+--------------------------+
| 1 | SIMPLE | ClusterMatches | range | PRIMARY | PRIMARY | 4 | NULL | 14938 | Using where; Using index |
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+--------------------------+
Сортировка Проблема
если я добавлю заказ суммой (tfdif) в
результат достаточно быстрый в этом масштабе, но имеющий ORDER BY SUM (tfidf) означает, что он использует временные и filesort
Возможные Решения?
Im ищет решение, которое не использует временное или filesort, вдоль линий
где мне не нужно жестко кодировать порог для total, любые идеи?