Вопрос

Я работал над запросом, который написал сегодня, и мне пришлось изменить код из WHERE предложение использовать фильтр IN (список вещей) вместо использования чего-то вроде

item_desc = 'item 1'
OR item_desc = 'item 2'
OR item_desc = 'item 3'
OR item_desc = 'item 4'

Вышеуказанное выполнялось в течение 15 минут и ничего не вернуло, но следующее дало мне результат за 1,5 минуты.

item_desc IN (
'item 1'
,'item 2'
,'item 3'
,'item 4'
)

Я сделал это в SQL, и мне интересно, почему IN (список элементов) выполняется намного быстрее, чем оператор OR.

- РЕДАКТИРОВАТЬ- SQL Server 2008, я извиняюсь за то, что в первую очередь не вкладывал эту информацию.

Вот запрос полностью с использованием OR заявления:

DECLARE @SD DATETIME
DECLARE @ED DATETIME
SET @SD = '2013-06-01';
SET @ED = '2013-06-15';

-- COLUMN SELECTION
SELECT PV.PtNo_Num AS 'VISIT ID'
, PV.Med_Rec_No AS 'MRN'
, PV.vst_start_dtime AS 'ADMIT'
, PV.vst_end_dtime AS 'DISC'
, PV.Days_Stay AS 'LOS'
, PV.pt_type AS 'PT TYPE'
, PV.hosp_svc AS 'HOSP SVC'
, SO.ord_no AS 'ORDER NUMBER'
--, SO.ent_dtime AS 'ORDER ENTRY TIME'
--, DATEDIFF(HOUR,PV.vst_start_dtime,SO.ent_dtime) AS 'ADM TO ENTRY HOURS'
, SO.svc_desc AS 'ORDER DESCRIPTION'
, OSM.ord_sts AS 'ORDER STATUS'
, SOS.prcs_dtime AS 'ORDER STATUS TIME'
, DATEDIFF(DAY,PV.vst_start_dtime,SOS.prcs_dtime) AS 'ADM TO ORD STS IN DAYS'

-- DB(S) USED
FROM smsdss.BMH_PLM_PtAcct_V PV
JOIN smsmir.sr_ord SO
ON PV.PtNo_Num = SO.episode_no
JOIN smsmir.sr_ord_sts_hist SOS
ON SO.ord_no = SOS.ord_no
JOIN smsmir.ord_sts_modf_mstr OSM
ON SOS.hist_sts = OSM.ord_sts_modf_cd

-- FILTER(S)
WHERE PV.Adm_Date BETWEEN @SD AND @ED
AND SO.svc_cd = 'PCO_REMFOLEY'
OR SO.svc_cd = 'PCO_INSRTFOLEY'
OR SO.svc_cd = 'PCO_INSTFOLEY'
OR SO.svc_cd = 'PCO_URIMETER'

AND SO.ord_no NOT IN (
    SELECT SO.ord_no
    FRROM smsdss.BMH_PLM_PtAcct_V PV
    JOIN smsmir.sr_ord SO
    ON PV.PtNo_Num = SO.episode_no
    JOIN smsmir.sr_ord_sts_hist SOS
    ON SO.ord_no = SOS.ord_no
    JOIN smsmir.ord_sts_modf_mstr OSM
    ON SOS.hist_sts = OSM.ord_sts_modf_cd
    WHERE OSM.ord_sts = 'DISCONTINUE'
    AND SO.svc_cd = 'PCO_REMFOLEY'
    OR SO.svc_cd = 'PCO_INSRTFOLEY'
    OR SO.svc_cd = 'PCO_INSTFOLEY'
    OR SO.svc_cd = 'PCO_URIMETER'
)
ORDER BY PV.PtNo_Num, SO.ord_no, SOS.prcs_dtime

Спасибо,

Это было полезно?

Решение

Ответ Олесского неверен.Для SQL Server 2008 IN список реорганизуется в серию OR заявления.В MySQL, скажем, все может быть иначе.

Я совершенно уверен, что если бы вы создали реальные планы выполнения для обоих ваших запросов, они были бы идентичны.

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

Обновлять

Фактический источник дисперсии, скорее всего, заключается в том, что запросы не эквивалентно.У тебя есть два разных OR списки ниже:

WHERE PV.Adm_Date BETWEEN @SD AND @ED
AND SO.svc_cd = 'PCO_REMFOLEY'
OR SO.svc_cd = 'PCO_INSRTFOLEY'
OR SO.svc_cd = 'PCO_INSTFOLEY'
OR SO.svc_cd = 'PCO_URIMETER'

и позже

 WHERE OSM.ord_sts = 'DISCONTINUE'
    AND SO.svc_cd = 'PCO_REMFOLEY'
    OR SO.svc_cd = 'PCO_INSRTFOLEY'
    OR SO.svc_cd = 'PCO_INSTFOLEY'
    OR SO.svc_cd = 'PCO_URIMETER'

В обоих тех WHERE Приоритет операторов (где AND обрабатывается перед OR) означает, что фактическая логика, выполняемая механизмом:

WHERE (ConditionA AND ConditionB)
OR ConditionC
OR ConditionD
OR ConditionE

Если вы замените OR списки с IN выражение, логика будет такой:

WHERE ConditionA
AND (ConditionB OR ConditionC OR ConditionD OR ConditionE)

Что радикально отличается.

Другие советы

Лучший способ узнать это — посмотреть на фактический план запроса, используя что-то вроде EXPLAIN.Это должно точно сказать вам, что делает СУБД, и тогда вы сможете гораздо лучше понять, почему она более эффективна.

С учетом сказанного, системы СУБД действительно хорошо справляются с операциями между двумя таблицами (например, соединениями).На эти части запросов тратится много времени оптимизатора, поскольку они, как правило, более затратны.

Например, СУБД могла бы отсортировать это IN список и, используя индекс на item_desc, фильтруйте результаты очень быстро.Вы не сможете выполнить такую ​​оптимизацию, если перечислите несколько вариантов, как в первом примере.

Когда вы используете IN, вы создаете импровизированную таблицу и фильтруете ее, используя более эффективные методы объединения таблиц.

РЕДАКТИРОВАТЬ:Я опубликовал этот ответ до того, как ОП упомянул конкретную СУБД.Оказывается, это НЕ то, как SQL Server обрабатывает этот запрос, но может быть справедливо для других систем СУБД.Видеть Ответ JNK для более конкретного и точного ответа.

Лицензировано под: CC-BY-SA с атрибуция
scroll top