Подзапросы и кэш MySQL для 18-метровой таблицы строки
-
27-09-2019 - |
Вопрос
Как это мой первый пост, кажется, я могу только опубликовать 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 с.
Применение
- Содержание таблицы можно предположить быть статическим.
- Низкое количество одновременных пользователей
- Запрос выше в настоящее время является единственным запросом, который будет работать на столе
Подзапрос
На основании этого поста [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] Я считаю, что значения, которые мне нужно настроить
- table_cache.
- key_buffer.
- sort_buffer.
- read_buffer_size.
- recort_rnd_buffer (для группы по запросу по условиям)
Области, определенные для улучшения - MySQL Query Tweaks
- Изменение данных DataType для сопоставления к индексу, который является INT, указывая на другую таблицу [MySQL, действительно, использует динамический формат строки, если он содержит поля переменной длины, такие как текст или BLOB, который в этом случае сортировка должна быть сделана на диске Отказ Раствор не должен выдержать эти типы данных, а скорее разделить такие поля в связанную таблицу.] [4
- Индексирование нового Match_index Feild, чтобы группа по
matches
Происходит быстрее, исходя из утверждения [«Вы, вероятно, должны создавать индексы для любого поля, на котором вы выбираете, группировать, заказывать или присоединение».] [5
Инструменты
Twak Выполните я планирую использовать
- Объясните] [6] Создание ссылки на [Выходной формат] [7
- AB - APACHE HTTP Server Benchmarking Tool] [8
- Профилирование] [9] с [Данными журнала] [10] [10
Будущий размер базы данных
Цель состоит в том, чтобы построить систему, которая может иметь 1 м уникальные значения CLUSTER_INDEX 1M уникальные значения совпадения, приблизительно приблизительно 3 000 000 000 столярных строк с временем отклика в запрос около 0,5с (мы можем добавить больше оперативной памяти и распространять базу данных через кластер)
Вопросы
- Я думаю, что мы хотим сохранить всю запись в RAM, чтобы запрос не прикоснулся к диску, если мы сохраним всю базу данных в кэше MySQL, что устраняет необходимость в MemcachedB?
- Пытается сохранить всю базу данных в кэше MySQL плохую стратегию, так как ее не предназначена для постоянного? Что-то подобное memcachedb или redis будет лучшим подходом, если так же почему?
- Является ли временная таблица «результат», которая создается запросом, автоматически уничтоженным при заканчивании запроса?
- Должны ли мы переключаться с InnoDB в MyiSam [так хорошо для чтения тяжелых данных, где, как innodb, хорошо для написания тяжелых] [11]?
- Мой кеш не похоже на его ноль в моем [конфигурации кэша запроса] [12], почему запрос в настоящее время происходит быстрее во второй раз, когда я запускаю его?
- Могу ли я реструктурировать мой запрос, чтобы устранить «Использование временного» и «Использование файловой борты», если я должен использовать присоединение вместо подзапроса?
- Как вы просматриваете размер MySQL [Cache Data] [13]?
- Какие размеры для значений 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;
Где мне не нужно жесткокодировать порог для всего, любые идеи?