Оптимизировать MySQL InnoDB запрос для максимального количества - PullRequest
1 голос
/ 06 марта 2019

У меня есть таблица MySQL InnoDB с 5,7 млн ​​строк и размером 1,9 ГБ:

+-------------------+---------+------+-----+---------+----------------+
|       Field       |  Type   | Null | Key | Default |     Extra      |
+-------------------+---------+------+-----+---------+----------------+
| id                | int(20) | NO   | PRI | NULL    | auto_increment |
| listing_id        | int(20) | YES  |     | NULL    |                |
| listing_link      | text    | YES  |     | NULL    |                |
| transaction_title | text    | YES  |     | NULL    |                |
| image_thumb       | text    | YES  |     | NULL    |                |
| seller_link       | text    | YES  |     | NULL    |                |
| seller_name       | text    | YES  |     | NULL    |                |
| sale_date         | date    | YES  |     | NULL    |                |
+-------------------+---------+------+-----+---------+----------------+

Вот мои настройки my.ini для моего сервера ОЗУ 3 ГБ:

key_buffer = 16M
max_allowed_packet = 16M
sort_buffer_size = 8M
net_buffer_length = 8K
read_buffer_size = 2M
read_rnd_buffer_size = 16M
myisam_sort_buffer_size = 8M
log_error = "mysql_error.log"
innodb_autoinc_lock_mode=0
join_buffer_size = 8M
thread_cache_size = 8
thread_concurrency = 8
query_cache_size = 64M
query_cache_limit = 2M
ft_min_word_len = 4
thread_stack = 192K
tmp_table_size = 64M

innodb_buffer_pool_size = 2G
innodb_additional_mem_pool_size = 16M
innodb_log_file_size = 512M
innodb_log_buffer_size = 8M
innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 120
innodb_write_io_threads = 8
innodb_read_io_threads = 8
innodb_thread_concurrency = 16
innodb_log_files_in_group = 3
innodb_max_dirty_pages_pct = 90

Когда я запускаю следующий запрос, для возврата результатов требуется более 20 минут:

SELECT transaction_title, 
       listing_id, 
       seller_name, 
       Max(sale_date) AS sale_date, 
       Count(*)       AS count 
FROM   sales_meta 
WHERE `sale_date` BETWEEN '2017-06-06' AND '2017-06-06' 
GROUP  BY listing_id 
HAVING Count(*) > 1 
ORDER  BY count DESC, 
          seller_name;

Я провел некоторое исследование, и, похоже, мне нужно добавить несколько индексов, чтобы ускорить процесс, но я не совсем понимаю, как это сделать. Есть несколько индексов с одним столбцом и несколько индексов с несколькими столбцами, что мне делать?

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

SELECT * 
FROM   sales_meta 
WHERE ` sale_date `= '2017-06-06'; 

и

SELECT DISTINCT `seller_name` 
FROM   `sales_meta`; 

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

Ответы [ 3 ]

1 голос
/ 06 марта 2019

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

    SELECT transaction_title, 
           listing_id, 
           seller_name, 
           Max(sale_date) AS max_sale_date, 
           Count(*)       AS count 
    FROM   sales_meta 
    WHERE sale_date =  str_to_date('2017-06-06', '%Y-%m-%d')  
    GROUP  BY listing_id 
    HAVING Count(*) > 1 
    ORDER  BY count DESC, seller_name;

и убедитесь, что у вас есть индекс на продажу_дата

0 голосов
/ 10 марта 2019
INDEX(sale_date) -- very important for the first query

str_to_date('2017-06-06', '%Y-%m-%d') -- no better than '2017-06-06'

innodb_buffer_pool_size = 2G  -- too big for your tiny RAM; change to 1G (swapping kills perf)

GROUP  BY listing_id  -- meaningless, since `listing_id` is unique; hence count is always 1

Prefer using an explicit list instead of `SELECT *`

SELECT DISTINCT `seller_name` 
    FROM   `sales_meta`;       -- needs INDEX(seller_name)

but `seller_name` needs to be a VARCHAR, not TEXT

Еще одно доказательство того, что str_to_date бесполезен:

mysql> SELECT STR_TO_DATE('2019-02-27', '%Y-%m-%d');
+---------------------------------------+
| STR_TO_DATE('2019-02-27', '%Y-%m-%d') |
+---------------------------------------+
| 2019-02-27                            |
+---------------------------------------+
0 голосов
/ 06 марта 2019
  • Похоже, что индекс на sale_date - это определенно то, что вы должны добавить в качестве пары запросов в вопросе: sale_date
  • Другим предложением является индексирование столбца, используемого в GROUP BY согласно документации MySQL

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

...