Подзапросы и Кэш 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.

использование


  1. содержимое таблицы можно считать статическим.
  2. низкое количество одновременных пользователей
  3. запрос выше в настоящее время является единственным запросом, который будет выполняться в таблице

подзапрос


на основе этого сообщения [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] я считаю, что значения, которые мне нужно настроить, являются

  1. table_cache
  2. key_buffer
  3. sort_buffer
  4. read_buffer_size
  5. record_rnd_buffer (для групп и порядка по условиям)

области, определенные для улучшения - MySQL query tweaks


  1. изменение типа данных для соответствий индексу, который является int, указывающим на другую таблицу [MySQL действительно будет использовать динамический формат строки, если он содержит поля переменной длины, такие как TEXT или BLOB, что в данном случае означает, что сортировка должна выполняться на диске. Решение состоит не в том, чтобы избегать этих типов данных, а в том, чтобы разделить такие поля на связанную таблицу.][4]
  2. индексирование нового поля match_index так, чтобы группа по matches происходит быстрее, на основе оператора ["вы, вероятно, должны создавать индексы для любого поля, на котором вы выбираете, группируете, упорядочиваете или присоединение."][5]

инструменты


для настройки выполнения я планирую использовать

  1. [Explain][6] ссылка на [выходной формат][7]
  2. [ab - Apache HTTP server инструмент бенчмаркинга] [8]
  3. [профилирование][9] С [данные журнала][10]

Будущий Размер Базы Данных


цель состоит в том, чтобы построить систему, которая может иметь 1M уникальных значений cluster_index 1M уникальных значений соответствия, прибл 3,000,000,000 строк таблицы со временем ответа на запрос около 0,5 С (при необходимости мы можем добавить больше ОЗУ и распределить базу данных по кластеру)

вопросы


  1. я думаю, что мы хотим сохранить весь набор записей в ОЗУ, чтобы запрос не касался диска, если мы сохраняем всю базу данных в кэше MySQL, это устраняет необходимость в memcachedb?
  2. пытается сохранить всю базу данных в кэше MySQL плохой стратегией, как он не предназначен, чтобы быть настойчивым? Было бы что-то вроде memcachedb или redis лучшим подходом, если да, то почему?
  3. временная таблица "результат", которая создается запросом, автоматически уничтожается по завершении запроса?
  4. должны ли мы переключиться с Innodb на MyISAM [как хорошо для чтения тяжелых данных, где InnoDB хорош для записи тяжелых] [11]?
  5. мой кэш не отображается как ноль в моей [конфигурации кэша запросов][12], Почему запрос в настоящее время происходит быстрее, когда я запускаю его во второй раз?
  6. могу ли я реструктурировать свой запрос, чтобы исключить" использование временного "и" использование filesort", должен ли я использовать соединение вместо подзапроса?
  7. как просмотреть размер MySQL [кэш данных][13]?
  8. какие размеры для значений 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, любые идеи?