Pracowałem z zapytaniem, które napisałem dzisiaj, musiałem zmienić kod z WHERE
klauzuli, aby użyć filtra IN (lista rzeczy) zamiast używać czegoś w rodzaju
item_desc = 'item 1'
OR item_desc = 'item 2'
OR item_desc = 'item 3'
OR item_desc = 'item 4'
Powyższe działało przez 15 minut i nic nie zwróciło, ale poniższe wyniki dały mi zestaw wyników w 1,5 minuty
item_desc IN (
'item 1'
,'item 2'
,'item 3'
,'item 4'
)
Zrobiłem to w SQL i zastanawiam się, dlaczego IN (lista elementów) działał o wiele szybciej niż instrukcja OR.
- EDYCJA - SQL Server 2008, przepraszam, że nie umieściłem tej części informacji na pierwszym miejscu.
Oto zapytanie w całości przy użyciu OR
instrukcji:
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
Dziękuję Ci,
OR
tak jak w powyższym zapytaniu, pozwalasz na zwarcie silnika.WHERE A AND B OR C
oceni prawdę, nawet jeśli A i B są fałszywe, jeśli C jest prawdą. Jeśli powieszWHERE A and B OR C OR D OR E OR F
tak jak powyżej,AND
możesz to rozłożyć na czynniki. Rzeczywista równoważne logika kapsułkowaniaOR
szereg powyżej w nawiasach są więc traktowane jako zestawyWHERE A AND (B OR C OR D OR E)
. Tak sięIN
leczy.AND
jest obsługiwana wcześniejOR
, więc powyższe zapytanie jest równoważne,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'
co oznacza, że jeśli którykolwiek z 3 ostatnich warunków jest spełniony, będzie w stanie zewrzeć resztę oceny.Odpowiedzi:
Odpowiedź Oleskiego jest nieprawidłowa. W przypadku SQL Server 2008
IN
lista jest refaktoryzowana do szereguOR
instrukcji. Może być inaczej, powiedzmy MySQL.Jestem całkiem pewien, że jeśli wygenerowałbyś rzeczywiste plany wykonania dla obu zapytań, byłyby one identyczne.
Najprawdopodobniej drugie zapytanie przebiegło szybciej, ponieważ uruchomiono je na drugim miejscu , a pierwsze zapytanie już wyciągnęło wszystkie strony danych z bazy danych i pokryło koszty zamówienia. Drugie zapytanie było w stanie odczytać wszystkie dane z pamięci i wykonać je znacznie szybciej.
Aktualizacja
Rzeczywiste źródło wariancji prawdopodobnie nie jest równoważne z zapytaniami . Masz dwie różne
OR
listy poniżej:i później
W obu tych
WHERE
klauzulach operator ma pierwszeństwo (gdzie AND jest obsługiwane przed OR) oznacza, że rzeczywista logika uruchomiona przez silnik to:Jeśli zastąpisz
OR
listyIN
wyrażeniem, logika będzie wyglądać następująco:Co jest zupełnie inne.
źródło
IN
nie jest równoważne zOR
powyższymi ze względu na inne warunki wWHERE
klauzuli w rzeczywistym zapytaniu. Zasadniczo zapytania zwrócą różne wyniki.Najlepszym sposobem na to jest sprawdzenie rzeczywistego planu zapytań przy użyciu czegoś takiego
EXPLAIN
. To powinno dokładnie powiedzieć, co robi DBMS, a następnie możesz uzyskać znacznie lepszy pomysł, dlaczego jest bardziej wydajny.To powiedziawszy, systemy DBMS są naprawdę dobre w wykonywaniu operacji między dwiema tabelami (jak sprzężenia). Dużo czasu optymalizatora spędza się na tych częściach zapytań, ponieważ są one na ogół droższe.
Na przykład DBMS może sortować tę
IN
listę i, używając indeksuitem_desc
, bardzo szybko filtrować wyniki. Nie możesz wykonać tej optymalizacji, gdy podajesz listę wybranych opcji, jak w pierwszym przykładzie.Kiedy używasz
IN
, tworzysz zaimprowizowaną tabelę i filtrujesz za pomocą tych bardziej wydajnych technik łączenia tabel.EDYCJA : Opublikowałem tę odpowiedź, zanim OP wspomniał o konkretnym DBMS. Okazuje się, że NIE jest to, w jaki sposób SQL Server traktuje to zapytanie, ale może być poprawne dla innych systemów DBMS. Zobacz odpowiedź JNK, aby uzyskać bardziej szczegółową i dokładną odpowiedź.
źródło
IN
nie będzie tak szybko, jakby to był SUBSELECT 100 zapisów w nim, czy tysiąc.IN
instrukcja nie jest konwertowana na tabelę, jest traktowana identycznie jak seriaOR
s.