MySQL проблема производительности в запросе выбора с объединением и группировкой по предложению - PullRequest
1 голос
/ 21 февраля 2020

Я сталкиваюсь с проблемой производительности при запросе таблицы с приблизительно 700 000 записей. Запрос выполняется более 10 секунд в первый раз для указанного c item_id, если я изменяю значение item_id в запросе, выполнение запроса занимает примерно столько же времени. Однако последующий запрос для того же item_id выполняется быстро, если только сервер не перезапущен.

Я пытаюсь выполнить запрос: -

select SQL_NO_CACHE item_id, item_rate_id, invoice_type, sum(qty_computed) as qty
from transaction_item 
left join transaction_customer
       on transaction_item.invoice_id = transaction_customer.invoice_id 
where item_id = 17179
group by item_rate_id, invoice_type

Структура моей таблицы (InnoDB) - -

Таблица: Transaction_item (без первичного ключа, INDEX: item_id, содержит около 700 000 строк)

enter image description here

Таблицаaction_customer (первичный ключ: invoice_id, содержит около 100 000 строк) enter image description here

Выполнение объяснения по вышеуказанному запросу дает следующий вывод:

enter image description here

my.ini config

[mysqld]
query_cache_size=0
query_cache_type=0
innodb_buffer_pool_size = 1G

Любая помощь по тонкой настройке MySQL config / db schema будет высоко оценена.

Ответы [ 2 ]

1 голос
/ 21 февраля 2020

Ваша индексация не так уж плоха для запроса, который вы описали. Что ухудшает вашу производительность, так это то, что обе эти таблицы содержат значительное количество данных в каждой строке. Для запроса нужны элементы из каждой таблицы, которых нет во вторичном индексе, и поэтому большие куски для таблицы, относящейся к указанному элементу, должны быть в пуле буферов innodb. Я не смотрел на точные цифры, однако 1G кажется недостаточным, и ваши описания запроса ускоряются во второй раз, кажется, поддерживают это (особенно с SQL_NO_CACHE и кэшем запросов отключенным (хорошо, что он отключен) .

Рекомендация 1. Увеличьте размер * 1004. * Посмотрите на SHOW GLOBAL STATUS LIKE 'innodb_buffer_pool%' и посмотрите количество элементов, удаленных из буфера между запросами.

Если вы действительно застряли в ОЗУ доступны и следуют теме рекомендаций @Drapp по индексам, что позволит использовать пул буферов innodb только с индексами, а не с полной таблицей. С этим innodb_buffer_pool конкурируют другие запросы, поэтому следующие имеют ограниченное глобальное влияние.

Рекомендация 2: (если № 1 нельзя сделать)

ALTER TABLE transaction_item
DROP INDEX item_id
ADD INDEX item_id (item_id, item_rate_id, qty_computed );

ALTER TABLE transaction_customer
ADD INDEX id_type (invoice_id, invoice_type);

Примечание: удалена сортировка, необходима для GROUP BY. Спасибо Рик

0 голосов
/ 21 февраля 2020

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

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

Я бы создал индекс для вашей таблицы Transaction_Item на (item_id, item_rate_id, invoice_id)

Кроме того, на вашей таблице Transaction_Customer есть индекс на (Invoice_id, Invoice_Type)

select SQL_NO_CACHE 
        ti.item_id, 
        ti.item_rate_id, 
        tc.invoice_type, 
        sum(ti.qty_computed) as qty
    from 
        transaction_item ti
            left join transaction_customer tc
                on ti.invoice_id = tc.invoice_id 
    where 
        ti.item_id = 17179
    group by 
        ti.item_rate_id, 
        tc.invoice_type
...