Подзапросы и кэш MySQL для 18-метровой таблицы строки

StackOverflow https://stackoverflow.com/questions/4265544

Вопрос

Как это мой первый пост, кажется, я могу только опубликовать 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 ГБ ОЗУ

Информация о таблице


Мой стол 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 и 6K уникальных совпадений. Запрос 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 строк и занимает примерно 15, когда тот же запрос запускается снова, требуется примерно 1 с.

Применение


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

Подзапрос


На основании этого поста [Stackoverflow: кэш / повторно используйте подзапрос в 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               |
+---------------------------------+----------------------+

На основании этой статьи о [Performance баз данных MySQL) [3] Я считаю, что значения, которые мне нужно настроить

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

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


  1. Изменение данных DataType для сопоставления к индексу, который является INT, указывая на другую таблицу [MySQL, действительно, использует динамический формат строки, если он содержит поля переменной длины, такие как текст или BLOB, который в этом случае сортировка должна быть сделана на диске Отказ Раствор не должен выдержать эти типы данных, а скорее разделить такие поля в связанную таблицу.] [4
  2. Индексирование нового Match_index Feild, чтобы группа по matches Происходит быстрее, исходя из утверждения [«Вы, вероятно, должны создавать индексы для любого поля, на котором вы выбираете, группировать, заказывать или присоединение».] [5

Инструменты


Twak Выполните я планирую использовать

  1. Объясните] [6] Создание ссылки на [Выходной формат] [7
  2. AB - APACHE HTTP Server Benchmarking Tool] [8
  3. Профилирование] [9] с [Данными журнала] [10] [10

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


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

Вопросы


  1. Я думаю, что мы хотим сохранить всю запись в RAM, чтобы запрос не прикоснулся к диску, если мы сохраним всю базу данных в кэше MySQL, что устраняет необходимость в MemcachedB?
  2. Пытается сохранить всю базу данных в кэше MySQL плохую стратегию, так как ее не предназначена для постоянного? Что-то подобное memcachedb или redis будет лучшим подходом, если так же почему?
  3. Является ли временная таблица «результат», которая создается запросом, автоматически уничтоженным при заканчивании запроса?
  4. Должны ли мы переключаться с InnoDB в MyiSam [так хорошо для чтения тяжелых данных, где, как innodb, хорошо для написания тяжелых] [11]?
  5. Мой кеш не похоже на его ноль в моем [конфигурации кэша запроса] [12], почему запрос в настоящее время происходит быстрее во второй раз, когда я запускаю его?
  6. Могу ли я реструктурировать мой запрос, чтобы устранить «Использование временного» и «Использование файловой борты», если я должен использовать присоединение вместо подзапроса?
  7. Как вы просматриваете размер MySQL [Cache Data] [13]?
  8. Какие размеры для значений table_cache, key_buffer, sort_buffer, read_buffer_size, recort_rnd_buffer вы бы предложили в качестве отправной точки?

Ссылки


  • 1: stackoverflow.com/questions/658937/cache-ru-use-a-subquery-in-mysql.
  • 2: databasejournal.com/features/mysql/article.php/10897_1382791_4/optimizze-mysql-queries-and-indexes.htm.
  • 3: Debianhelp.co.uk/mysqlperformance.htm.
  • 4: 20bits.com/articles/10-Tips-for-optimizze-mysql-queries-that-dont-suck/
  • 5: 20bits.com/articles/10-Tips-for-optimizze-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-optimizze-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.
Это было полезно?

Решение

Изменение таблицы


На основании совета в этом посте на Как выбрать индексы для заказа BY и Group по запросам Таблица теперь выглядит как

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;

Который устраняет, используя временные и использование файловой

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

Проблема сортировки

Однако, если я добавлю порядок по SUM (TFDIF) в

SELECT match_index, SUM(tfidf) AS total FROM ClusterMatches
WHERE cluster_index in (1,2,3 ... 3000) GROUP BY match_index 
ORDER BY total DESC LIMIT 0,10;
+-------------+--------------------+
| match_index | total              |
+-------------+--------------------+
|         868 |   0.11126546561718 | 
|        4182 | 0.0238558370620012 | 
|        2162 | 0.0216601379215717 | 
|        1406 | 0.0191618576645851 | 
|        4239 | 0.0168981291353703 | 
|        1437 | 0.0160425212234259 | 
|        2599 | 0.0156466849148273 | 
|         394 | 0.0155945559963584 | 
|        3116 | 0.0151005545631051 | 
|        4028 | 0.0149106932803988 | 
+-------------+--------------------+
10 rows in set (0.03 sec)

Результат достаточно быстрый в этой шкале, но имеющий Порядок по сумме (TFIDF) означает, что он использует временный и файловый

explain extended SELECT match_index, SUM(tfidf) AS total FROM ClusterMatches 
WHERE cluster_index IN (1,2,3 ... 3000) GROUP BY match_index 
ORDER BY total DESC LIMIT 0,10;
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------------+
| id | select_type | table                | type  | possible_keys | key     | key_len | ref  | rows  | Extra                                                     |
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------------+
|  1 | SIMPLE      | ClusterMatches       | range | PRIMARY       | PRIMARY | 4       | NULL | 65369 | Using where; Using index; Using temporary; Using filesort | 
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------------+

Возможные решения?

Я ищу решение, которое не использует временный или файловый борт, вдоль линий

SELECT match_index, SUM(tfidf) AS total FROM ClusterMatches 
WHERE cluster_index IN (1,2,3 ... 3000) GROUP BY cluster_index, match_index 
HAVING total>0.01 ORDER BY cluster_index;
Где мне не нужно жесткокодировать порог для всего, любые идеи?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top