2016-05-24 2 views
0

У меня эти таблицы в MySQL.Улучшение SQL в MySQL

CREATE TABLE `tableA` (
    `id_a` int(11) NOT NULL, 
    `itemCode` varchar(50) NOT NULL, 
    `qtyOrdered` decimal(15,4) DEFAULT NULL, 
      : 
    PRIMARY KEY (`id_a`), 
    KEY `INDEX_A1` (`itemCode`) 
) ENGINE=InnoDB 

CREATE TABLE `tableB` (
    `id_b` int(11) NOT NULL AUTO_INCREMENT, 
    `qtyDelivered` decimal(15,4) NOT NULL, 
    `id_a` int(11) DEFAULT NULL, 
    `opType` int(11) NOT NULL, -- '0' delivered to customer, '1' returned from customer 
        : 
    PRIMARY KEY (`id_b`), 
    KEY `INDEX_B1` (`id_a`) 
    KEY `INDEX_B2` (`opType`) 
) ENGINE=InnoDB 

tableA показывает, сколько количества мы получили заказ от клиента, tableB показывает, сколько количества мы поставили к клиенту для каждого заказа.

Я хочу сделать SQL, который подсчитывает количество оставшегося количества для доставки по каждому itemCode. SQL выглядит следующим образом. Этот SQL работает, но медленный.

SELECT T1.itemCode, 
     SUM(IFNULL(T1.qtyOrdered,'0')-IFNULL(T2.qtyDelivered,'0')+IFNULL(T3.qtyReturned,'0')) as qty 
FROM tableA AS T1 
LEFT JOIN (SELECT id_a,SUM(qtyDelivered) as qtyDelivered FROM tableB WHERE opType = '0' GROUP BY id_a) 
    AS T2 on T1.id_a = T2.id_a 
LEFT JOIN (SELECT id_a,SUM(qtyDelivered) as qtyReturned FROM tableB WHERE opType = '1' GROUP BY id_a) 
    AS T3 on T1.id_a = T3.id_a 
WHERE T1.itemCode = '?' 
GROUP BY T1.itemCode 

Я попытался explain на этом SQL, и результат, как показано ниже.

+----+-------------+------------+------+----------------+----------+---------+-------+-------+----------------------------------------------+ 
| id | select_type | table  | type | possible_keys | key  | key_len | ref | rows | Extra          | 
+----+-------------+------------+------+----------------+----------+---------+-------+-------+----------------------------------------------+ 
| 1 | PRIMARY  | T1   | ref | INDEX_A1  | INDEX_A1 | 152  | const |  1 | Using where         | 
| 1 | PRIMARY  | <derived2> | ALL | NULL   | NULL  | NULL | NULL | 21211 |            | 
| 1 | PRIMARY  | <derived3> | ALL | NULL   | NULL  | NULL | NULL | 10 |            | 
| 3 | DERIVED  | tableB  | ref | INDEX_B2  | INDEX_B2 | 4  |  | 96 | Using where; Using temporary; Using filesort | 
| 2 | DERIVED  | tableB  | ref | INDEX_B2  | INDEX_B2 | 4  |  | 55614 | Using where; Using temporary; Using filesort | 
+----+-------------+-------------------+----------------+----------+---------+-------+-------+----------------------------------------------+ 

Я хочу улучшить свой запрос. Как я могу это сделать?

ответ

1

Во-первых, ваша таблица B имеет int для opType, но вы сравниваете строку с '0' и '1'. Оставьте как числовые 0 и 1. Чтобы оптимизировать ваши предварительные агрегаты, вы не должны иметь индексы отдельных столбцов, а составные и в этом случае индекс покрытия. Таблица INDEX B ON (OpType, ID_A, QtyDelivered) как единый индекс. OpType оптимизирует WHERE, ID_A для оптимизации группы и QtyDelivered для агрегата в индексе без перехода на страницы необработанных данных.

Поскольку вы ищете два типа, вы можете сверлить их в одно тестирование подзапроса либо в результате одного прохода. ТОГДА, Присоединяйтесь к своим результатам.

SELECT 
     T1.itemCode, 
     SUM(IFNULL(T1.qtyOrdered, 0) 
     - IFNULL(T2.qtyDelivered, 0) 
     + IFNULL(T2.qtyReturned, 0)) as qty 
    FROM 
     tableA AS T1 
     LEFT JOIN (SELECT 
          id_a, 
          SUM(IF(opType=0,qtyDelivered, 0)) as qtyDelivered, 
          SUM(IF(opType=1,qtyDelivered, 0)) as qtyReturned 
         FROM 
          tableB 
         WHERE 
          opType IN (0, 1) 
         GROUP BY 
          id_a) AS T2 
      on T1.id_a = T2.id_a 
    WHERE 
     T1.itemCode = '?' 
    GROUP BY 
     T1.itemCode 

Теперь, в зависимости от размера таблиц, вы можете быть лучше делать JOIN на вашей внутренней таблицы в таблицу А так вы получите только те из кода элемента вы expectin. Если у вас есть 50 тыс. Элементов, и вы ищете только предметы, которые соответствуют 120 элементам, тогда ваш внутренний запрос будет STILL, который будет основываться на 50k. В этом случае было бы излишним. В этом случае, я хотел бы предложить индекс по таблице А по формуле (Артикул, ID_A) и настроить внутренний запрос

  LEFT JOIN (SELECT 
          b.id_a, 
          SUM(IF(b.opType = 0, b.qtyDelivered, 0)) as qtyDelivered, 
          SUM(IF(b.opType = 1, b.qtyDelivered, 0)) as qtyReturned 
         FROM 
          (select distinct id_a 
           from tableA 
           where itemCode = '?') pqA 
           JOIN tableB b 
           on PQA.id_A = b.id_a 
           AND b.opType IN (0, 1) 
         GROUP BY 
          id_a) AS T2 

My Query against your SQLFiddle

+0

Я не думаю, что есть какая-либо точка в 'WHERE opType IN (0 , 1) ', поскольку это единственные два возможных значения. – Barmar

+0

Спасибо за ответ. Но использование sub-запроса делает мой запрос медленным, я думаю. Я хочу исключить суб-запрос. Могу ли я сделать то же самое без подзапроса? –

+0

@ N.F., Какой подзапрос. Даже ваш первоначальный образец показывает TWO-подзапросы, из которых я сводился к одному и учитывал обе части в одном. Второй образец, опять же, основывался на количестве ваших данных, элементах и ​​запросил все независимо от элемента и присоединился к этому элементу. Вам нужно ПО ПОДРОБНОМУ 1 подзапрос, чтобы удалить ВОЗМОЖНЫЕ дублирования доставки/возврата. – DRapp

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