2013-09-20 3 views
1

У меня есть запрос, который я пытаюсь ускорить. Я уверен, что есть способ сделать это более эффективным, но у меня недостает знаний.Запрос MySQL с зависимыми подзапросами - как я могу ускорить его?

заказов - это показывает, одна строки за заказ получена (в настоящее время 800000 строк)

orders_financials - это показывает, по одной строке на финансовую операцию, связанную с порядком (в настоящее время 2000000 строк)

В таблице orders_financials будет содержать несколько строк на заказ, категория сделки показана на financialType

Так, например, для одного заказа там может быть 5 строк в orders_financials

financialType = 14: value = 10.00 
financialType = 12: value = 7.00 
financialType = 18: value = 2.50 
financialType = 15: value = 0.30 
financialType = 17: value = 7.50 

Для каждого заказа будет различный объем данных. Со временем в систему добавляется больше данных, и новые ряды добавляются в order_financial.

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

Запрос ниже должен дать мне все заказы, размещенные CUSTOMERID 279:

select 
orders.orderID, 
customers.username, 
(select group_concat(financialRef) from orders_financials where orders_financials.orderID=orders.orderID and financialType IN (17)) ref, 
(select sum(amount) from orders_financials where orders_financials.orderID=orders.orderID and financialType IN (17)) costs_cost, 
(select sum(amount) from orders_financials where orders_financials.orderID=orders.orderID and financialType IN (12,13)) costs_exp, 
(select sum(amount) from orders_financials where orders_financials.orderID=orders.orderID and financialType IN (14)) costs_sell, 
(select sum(amount) from orders_financials where orders_financials.orderID=orders.orderID and financialType IN (15)) costs_sell_out,          
(select sum(amount) from orders_financials where orders_financials.orderID=orders.orderID and financialType IN (1,2,3,9,11)) extras_in, 
(select sum(amount) from orders_financials where orders_financials.orderID=orders.orderID and financialType IN (4,5)) extras_out, 
(select sum(amount) from orders_financials where orders_financials.orderID=orders.orderID and financialType IN (20)) extras_back, 
(select sum(amount) from orders_financials where orders_financials.orderID=orders.orderID and financialType IN (18)) insurance_in, 
(select sum(amount) from orders_financials where orders_financials.orderID=orders.orderID and financialType IN (10,6)) insurance_out, 
(select sum(amount) from orders_financials where orders_financials.orderID=orders.orderID and financialType IN (19)) insurance_back            
from orders 
left join customers on orders.customerID=customers.customerID 
where customers.customerID='279' 
order by orderID 

(FYI, есть 18,263 записей в таблице заказов, где CUSTOMERID = 279)

Вы увидите, что financialType-х из 12 или 13 можно суммировать с cost_exp. Аналогично 1,2 3,9,11 - все extras_in.

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

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

Из лога медленного я могу видеть это перебором 422,000,000 строк

Query_time: 528.107584 Lock_time: 0.000652 Rows_sent: 1388 Rows_examined: 422442417 

Там должна быть более эффективным способом, но я изо все силы, чтобы увидеть.

EDIT - Вот EXPLAIN вышеуказанного запроса:

+----+--------------------+-------------------+-------+-----------------------+---------------+---------+---------------------------+--------+--------------------------+ 
| id | select_type  | table    | type | possible_keys   | key   | key_len | ref      | rows | Extra     | 
+----+--------------------+-------------------+-------+-----------------------+---------------+---------+---------------------------+--------+--------------------------+ 
| 1 | PRIMARY   | customers   | const | PRIMARY    | PRIMARY  | 4  | const      |  1 |       | 
| 1 | PRIMARY   | orders   | ref | customerID   | customerID | 5  | const      | 24802 | Using where; Using index | 
| 12 | DEPENDENT SUBQUERY | orders_financials | ref | orderID,financialType | financialType | 4  | const      |  1 | Using where    | 
| 11 | DEPENDENT SUBQUERY | orders_financials | range | orderID,financialType | financialType | 4  | NULL      |  2 | Using where    | 
| 10 | DEPENDENT SUBQUERY | orders_financials | ref | orderID,financialType | financialType | 4  | const      | 49717 | Using where    | 
| 9 | DEPENDENT SUBQUERY | orders_financials | ref | orderID,financialType | financialType | 4  | const      |  1 | Using where    | 
| 8 | DEPENDENT SUBQUERY | orders_financials | range | orderID,financialType | financialType | 4  | NULL      |  2 | Using where    | 
| 7 | DEPENDENT SUBQUERY | orders_financials | range | orderID,financialType | financialType | 4  | NULL      |  5 | Using where    | 
| 6 | DEPENDENT SUBQUERY | orders_financials | ref | orderID,financialType | financialType | 4  | const      | 139 | Using where    | 
| 5 | DEPENDENT SUBQUERY | orders_financials | ref | orderID,financialType | orderID  | 4  | p4db_admin.orders.orderID | 236338 | Using where    | 
| 4 | DEPENDENT SUBQUERY | orders_financials | ref | orderID,financialType | orderID  | 4  | p4db_admin.orders.orderID | 236338 | Using where    | 
| 3 | DEPENDENT SUBQUERY | orders_financials | ref | orderID,financialType | financialType | 4  | const      | 99966 | Using where    | 
| 2 | DEPENDENT SUBQUERY | orders_financials | ref | orderID,financialType | financialType | 4  | const      | 99966 | Using where    | 
+----+--------------------+-------------------+-------+-----------------------+---------------+---------+---------------------------+--------+--------------------------+ 
13 rows in set (0.00 sec) 
+0

показать нам объяснить этот запрос. Также подзапрос в mysql - это, как правило, очень медленная и болезненная вещь, поэтому, если вы собираетесь использовать их много, подумайте о переключении на mariadb. –

+0

Какие индексы у вас есть на таблицах? –

+0

Попробуйте добавить составной индекс на '(orderID, financialType, financialRef, amount)', а затем и ваш запрос, и переписать на @ 491243 –

ответ

4
SELECT a.orderID, 
     b.username, 
     GROUP_CONCAT(CASE WHEN c.financialType = 17 THEN c.financialRef END) ref, 
     SUM(CASE WHEN c.financialType IN (12,13) THEN c.amount END) costs_cost, 
     SUM(CASE WHEN c.financialType = 14 THEN c.amount END) costs_exp, 
     SUM(CASE WHEN c.financialType = 15 THEN c.amount END) costs_sell, 
     SUM(CASE WHEN c.financialType IN (1,2,3,9,11) THEN c.amount END) extras_in, 
     SUM(CASE WHEN c.financialType IN (4,5) THEN c.amount END) extras_out, 
     SUM(CASE WHEN c.financialType = 20 THEN c.amount END) extras_back, 
     SUM(CASE WHEN c.financialType = 18 THEN c.amount END) insurance_in, 
     SUM(CASE WHEN c.financialType IN (10,6) THEN c.amount END) insurance_out, 
     SUM(CASE WHEN c.financialType = 19 THEN c.amount END) insurance_back 
FROM orders a 
     LEFT JOIN customers b 
      ON a.customerID = b.customerID 
     LEFT JOIN orders_financials c 
      ON a.orderID = c.orderID 
GROUP BY a.orderID, b.username 

также добавить индекс на orders_financials.financialType

ALTER TABLE orders_financials ADD INDEX (financialType) 
+0

Это замечательно @ 491243 - большое вам спасибо. – Chris

+0

Просто еще один вопрос подумал. В order_financial может быть 10 строк для определенного идентификатора orderID.Один из них будет иметь финансовый тип 10, и у него есть соответствующий идентификатор carrierInvoiceID 12345 . Как я могу добавить запрос WHERE, чтобы получить все orderID из order_financial, где указаны финансовые тип = 10 и carrierInvoiceID = 12345, а затем для всех идентификаторов orderID, которые будут отображаться в мой стол и динамически рассчитанные итоговые значения? я использовал: a.orderID IN (выберите OrderId из orders_financials где carrierInvoiceID = '12345') Но это принимает возрастов, я предполагаю, что есть лучший способ @ 491243 – Chris

+0

'LEFT JOIN orders_financials с ON .orderID = c.orderID И c.carrierInvoiceID = '12345'' - это то, что вы хотите? не уверен. –

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