SQL - IN (Выбрать ...) Проблема производительности - PullRequest
0 голосов
/ 14 июня 2019

Я знаю, что в (выбрать ...) вещах следует избегать, но в моей ситуации я не мог найти другой способ сделать это.

К сожалению, поскольку база данных огромна, я бы хотел найти лучший способ.Не могли бы вы поделиться своим опытом оптимизации запроса ниже?

Вот идея БД

ID   OrderRef   Product    OrderDate   ShipmentDate    Client

1    111        T-Shirt    1/1/2018    4/1/2018        Georges
2    111        Pull-Over  1/1/2018    6/1/2018        (Unknown)
3    222        Shoes      9/1/2018    15/1/2018       Austin
4    222        T-Shirt    9/1/2018    18/1/2018       (Unknown)

Что мне нужно получить:

  • данные, связанные с порядком Жоржа (здесь строки 1 и 2).Но, как вы видите, клиент во втором ряду «неизвестен».
  • последняя дата отгрузки (-> max (t2.ShipmentDate)), связанная с конкретным заказом, сгруппированным по ссылке

Вот мой код

SELECT t1.OrderRef, t1.Product, t1.OrderDate, t1.Client, t4.max_date
FROM table1 as t1
RIGHT JOIN (SELECT t2.OrderRef, max(t2.ShipmentDate) as max_date
            FROM table1 as t2
            WHERE t2.OrderRef in(
                            SELECT t3.OrderRef 
                            FROM table1 as t3
                            WHERE t3.Client='Georges')
            GROUP BY t2.OrderRef) as t4 on t2.OrderRef=t1.OrderRef

Правое объединение предназначено для извлечения только ссылки OrderReference, связанной с Georges, и подзапроса для вычисления самой последней даты пересылки

  • Существует ли более эффективный способ достижения этого результата?
  • Какt1, t2, t3 связаны с одной и той же таблицей.Я думаю, что таким образом это более читабельно, но для эффективности я должен использовать только одно имя для них?

Заранее спасибо за помощь, Ларго

Ответы [ 2 ]

2 голосов
/ 14 июня 2019

Похоже, вы получаете несколько строк только для каждого вызова. Это должно быть довольно быстро, даже если у вас есть миллиарды строк. Я бы сделал что-то вроде:

with
a as (
  select max(orderref) as orderref
  from t
  where client = 'Georges'
),
b as (
  select t.* 
  from t
  join a on a.orderref = t.orderref
),
c as (
  select max(shipmentdate) as maxshipmentdate from b
)
select b.*, c.maxshipmentdate
from b
cross join c 

Запрос выше должен быть довольно быстрым, если у вас есть следующие индексы:

create index ix1 on t (client);
create index ix2 on t (orderref);
0 голосов
/ 14 июня 2019

Я бы попробовал использовать (коррелированные) подзапросы.

SELECT t11.orderref,
       t11.product,
       t11.orderdate,
       t11.client,
       (SELECT max(t13.shipmentdate)
               FROM table1 t13
               WHERE t13.orderref = t11.orderref) max_date
       FROM table1 t11
       WHERE t11.orderref = (SELECT t12.orderref
                                    FROM table1 t12
                                    WHERE t12.client = 'Georges');

Для поддержки подзапроса, получая orderref индекс как

CREATE INDEX table1_c_or
             ON table1 (client ASC,
                        orderref ASC);

должно помочь. Этот подзапрос в любом случае "заостренный".

Для получения максимума shipmentdate

CREATE INDEX table1_or_sd
             ON table1 (orderref ASC,
                        shipmentdate DESC);

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

При желании можно создать дополнительный индекс, например

CREATE INDEX table1_or_p_od_c
             ON table1 (orderref ASC,
                        product ASC,
                        orderdate ASC,
                        client ASC);

может даже лучше поддерживать внешний запрос. Но это не обязательно, я думаю.

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