2015-06-01 4 views
1

Я пытаюсь оптимизировать запрос, как показано ниже. У меня есть вопрос, как добавить индекс для улучшения производительности, но результат все еще медленный. Запрос выполнялся за 20 секунд, Transaction содержит около 100 тыс. Записей и объединяет таблицу TransactionDetail, содержащую около 500 тыс. Записей.Медленная производительность при соединении таблицы

SELECT Transaction.id .... 
    FROM Transaction 
    INNER JOIN Agent ON Agent.id = Transaction.agent_id 
    INNER JOIN Distributor ON Distributor.id = Transaction.distributor_id 
    INNER JOIN TransactionDetail ON Transaction.id = TransactionDetail.transaction_id 
    WHERE TransactionDetail.type = 'Admin' 
    AND Transaction.status IN ('pending', 'processing', 'success', 'rejected') 
    ORDER BY issued_date DESC LIMIT 0 , 10 

из запроса выше я пытаюсь применить то, что я понимаю, о индексации

  1. Я добавил 3 индекса из-за внутреннего соединения, транзакции (agent_id, distributor_id) и транзакций (TRANSACTION_ID)

  2. из где положение я добавил Transaction (статус)

  3. из ORDER BY Я добавил Сделка (issued_date)

Но он не показывает каких-либо улучшений ниже, что я получаю от EXPLAIN

enter image description here

И это скриншот из PHPMyAdmin, которые показывают индексирование таблицы транзакций

enter image description here

Есть ли способ улучшить этот запрос? Или он уже оптимизирован, и я должен сосредоточиться на конфигурации mysql?

+0

Пожалуйста, напишите мне комментарий, если вы думаете, что я должен добавить дополнительную информацию. –

ответ

1

Ваш запрос

SELECT Transaction.id .... 
FROM Transaction 
INNER JOIN Agent ON Agent.id = Transaction.agent_id 
INNER JOIN Distributor ON Distributor.id = Transaction.distributor_id 
INNER JOIN TransactionDetail ON Transaction.id = TransactionDetail.transaction_id 
WHERE TransactionDetail.type = 'Admin' 
AND Transaction.status IN ('pending', 'processing', 'success', 'rejected') 
ORDER BY issued_date DESC LIMIT 0 , 10 

Теперь у вас уже есть индексы, применяемые на столах, которые хорошо, однако in clause больше похож or и это создает реальную проблему производительности. В случае небольшого набора данных это невозможно было наблюдать, но в большом наборе данных производительность будет значительно снижена.

Один из методов оптимизации было бы преобразовать in clause в union, который работает лучше, чем orin

(
SELECT Transaction.id .... 
FROM Transaction 
INNER JOIN Agent ON Agent.id = Transaction.agent_id 
INNER JOIN Distributor ON Distributor.id = Transaction.distributor_id 
INNER JOIN TransactionDetail ON Transaction.id = TransactionDetail.transaction_id 
WHERE TransactionDetail.type = 'Admin' 
AND Transaction.status = 'pending' 
) 
union 
(
SELECT Transaction.id .... 
FROM Transaction 
INNER JOIN Agent ON Agent.id = Transaction.agent_id 
INNER JOIN Distributor ON Distributor.id = Transaction.distributor_id 
INNER JOIN TransactionDetail ON Transaction.id = TransactionDetail.transaction_id 
WHERE TransactionDetail.type = 'Admin' 
AND Transaction.status = 'processing' 
) 
union 
(
SELECT Transaction.id .... 
FROM Transaction 
INNER JOIN Agent ON Agent.id = Transaction.agent_id 
INNER JOIN Distributor ON Distributor.id = Transaction.distributor_id 
INNER JOIN TransactionDetail ON Transaction.id = TransactionDetail.transaction_id 
WHERE TransactionDetail.type = 'Admin' 
AND Transaction.status = 'success' 
) 
union 
(
SELECT Transaction.id .... 
FROM Transaction 
INNER JOIN Agent ON Agent.id = Transaction.agent_id 
INNER JOIN Distributor ON Distributor.id = Transaction.distributor_id 
INNER JOIN TransactionDetail ON Transaction.id = TransactionDetail.transaction_id 
WHERE TransactionDetail.type = 'Admin' 
AND Transaction.status = 'rejected' 
) 
order by issued_date DESC LIMIT 0 , 10 

Для решения заказа вам может понадобиться добавить индекс, как

alter table Transaction add index status_created_idx(status,issued_date); 
+0

Это замечательно, за исключением того, что это небольшой набор данных. – Strawberry

+1

@Strawberry для небольшого набора данных, имеющих индексы на 'status' и' issu_date', может решить проблему, даже для 100 тысяч записей я могу сказать, что результат должен быть возвращен в макс. –

+0

Не это * MY * пункт? ;-) – Strawberry

1

Добавление всего INDEXes бесполезно, поскольку оптимизатор (почти всегда) использует только один индекс.

Оригинальный запрос может получить выгоду от INDEX(issue_date). Добавьте этот индекс, затем покажите нам результат от EXPLAIN SELECT ..., чтобы узнать, использует ли он его.

Если он использует его, это принесет выгоду, если вы избежите «файлового управления», который обычно является лишь небольшой частью общего времени. Он также может выиграть от остановки из-за LIMIT. Тем не менее, вероятно, придется читать более 10 строк, так как WHERE содержит другие таблицы.

Из-за TransactionDetail.type = 'Admin' он должен пробиться через JOINs, прежде чем принимать решение о том, какие строки хранить.

Два вопроса, которые могут привести к другим вариантам:

  • Какой процент строк TransactionDetail имеют тип = 'Admin'?
  • Какой процент строк в транзакции имеет статус IN («ожидающий», «обработка», «успех», «отклонено»)?

Как вы экспериментируете, поставите (1) индексы и (2) EXPLAIN.

Смежные вопросы