Я работал с запросом, который я написал сегодня, должен был изменить код из 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
Спасибо,
OR
как вы делаете в фактическом запросе выше, вы позволяете двигателю к короткому замыканию.WHERE A AND B OR C
будет иметь значение true, даже если A и B ложны, если C истинно. Если вы говорите так же,WHERE A and B OR C OR D OR E OR F
как и выше, этоAND
может быть учтено. Фактическая эквивалентная логика инкапсулироватьOR
ряд выше в скобках , поэтому они рассматриваются как набор:WHERE A AND (B OR C OR D OR E)
. Вот как этоIN
лечится.AND
обрабатывался ранееOR
, поэтому приведенный выше запрос эквивалентен тому,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'
что означает, что если какое-либо из 3 последних условий выполнено, он сможет замкнуть остальную часть оценки.Ответы:
Ответ Олески неверен. Для SQL Server 2008
IN
список преобразуется в сериюOR
операторов. Это может быть иначе, скажем, в MySQL.Я совершенно уверен, что если вы сгенерируете реальные планы выполнения для обоих ваших запросов, они будут идентичны.
По всей вероятности, второй запрос был выполнен быстрее, потому что вы запустили его вторым , а первый запрос уже извлек все страницы данных из базы данных и оплатил стоимость ввода-вывода. Второй запрос смог прочитать все данные из памяти и выполнить намного быстрее.
Обновить
Фактический источник отклонения, вероятно, что запросы не эквивалентны . У вас есть два разных
OR
списка ниже:и позже
В обоих этих
WHERE
пунктах приоритет оператора (где AND обрабатывается перед OR) означает, что фактическая логика, выполняемая механизмом:Если вы замените
OR
спискиIN
выражением, логика будет такой:Что в корне отличается.
источник
IN
не эквивалентно вашемуOR
выше из-за других условий в вашемWHERE
предложении в фактическом запросе. В основном запросы будут давать разные результаты.Лучший способ узнать это - посмотреть на фактический план запроса, используя что-то вроде
EXPLAIN
. Это должно точно сказать вам, что делает СУБД, и тогда вы сможете лучше понять, почему она более эффективна.При этом системы СУБД действительно хороши для выполнения операций между двумя таблицами (например, объединениями). Много времени оптимизатора тратится на эти части запросов, потому что они обычно более дороги.
Например, СУБД может отсортировать этот
IN
список и, используя индексitem_desc
, очень быстро отфильтровать результаты. Вы не можете сделать эту оптимизацию, когда вы перечисляете кучу выборов, как в первом примере.Когда вы используете
IN
, вы создаете импровизированную таблицу и фильтруете, используя эти более эффективные методы объединения таблиц.РЕДАКТИРОВАТЬ : Я опубликовал этот ответ, прежде чем OP упомянул конкретные СУБД. Оказывается, это НЕ так, как SQL Server обрабатывает этот запрос, но может быть допустимым для других систем СУБД. См . Ответ JNK для более точного и точного ответа.
источник
IN
не было бы так быстро, если бы это был отбор с 100 записями или тысячами.IN
оператор не преобразуется в таблицу, он обрабатывается идентично серииOR
s.