UNION ALL Optimization
két vagy több adatkészlet összefűzése leggyakrabban T-SQL-ben fejeződik ki a UNION ALL
záradék használatával. Tekintettel arra, hogy az SQL Server optimizer gyakran átrendezni a dolgokat, mint csatlakozik, valamint aggregátumok, hogy a teljesítmény javítása érdekében, ez teljesen reális, hogy az SQL Server is figyelembe vennék átrendezéséhez összefűzés bemenet, amennyiben ez előnyt. Például az optimalizáló figyelembe veheti a A UNION ALL B
mint B UNION ALL A
átírásának előnyeit.
valójában az SQL Server optimizer ezt nem teszi meg. Pontosabban, volt némi korlátozott támogatást concatenation bemenet átrendezése SQL Server kiadások akár 2008 R2, de ezt eltávolították az SQL Server 2012, és nem bukkant fel azóta.
SQL Server 2008 R2
intuitív módon a konkatenációs bemenetek sorrendje csak akkor számít, ha van sorcél. Alapértelmezés szerint az SQL Server optimalizálja a végrehajtási terveket annak alapján, hogy az összes minősítő sor visszatér az ügyfélhez. Amikor egy sorcél van érvényben, az optimalizáló megpróbál olyan végrehajtási tervet találni, amely gyorsan elkészíti az első néhány sort.
A Sorcélok többféle módon állíthatók be, például a TOP
, a FAST n
lekérdezési tipp, vagy a EXISTS
használatával (amelyet természeténél fogva legfeljebb egy sorban kell megtalálni). Ahol nincs sorcél (azaz az ügyfél minden sort igényel), általában nem számít, hogy a konkatenációs bemenetek melyik sorrendben olvasódnak: minden bemenet végül minden esetben teljes mértékben feldolgozásra kerül.
az SQL Server 2008 R2-ig terjedő verziók korlátozott támogatása akkor érvényes, ha pontosan egy sor célja van. Ebben a konkrét körülmények között az SQL Server átrendezi a konkatenációs bemeneteket a várható költségek alapján.
Ez nem a költségalapú optimalizálás során történik( ahogy az elvárható), hanem inkább a normál optimalizáló kimenet utolsó perces optimalizálási átírása. Ennek az elrendezésnek az az előnye, hogy nem növeli a költségalapú tervkeresési helyet (potenciálisan egy alternatíva minden lehetséges átrendezéshez), miközben még mindig olyan tervet készít, amely optimalizálva van az első sor gyors visszatéréséhez.
példák
a következő példák két azonos tartalmú táblát használnak: egy millió sor egész szám egytől egy millióig. Az egyik asztal egy halom, nem záródó indexekkel; a másiknak egyedi fürtözött indexe van:
CREATE TABLE dbo.Expensive( Val bigint NOT NULL); CREATE TABLE dbo.Cheap( Val bigint NOT NULL, CONSTRAINT UNIQUE CLUSTERED (Val));GOINSERT dbo.Cheap WITH (TABLOCKX) (Val)SELECT TOP (1000000) Val = ROW_NUMBER() OVER (ORDER BY SV1.number)FROM master.dbo.spt_values AS SV1CROSS JOIN master.dbo.spt_values AS SV2ORDER BY ValOPTION (MAXDOP 1);GOINSERT dbo.Expensive WITH (TABLOCKX) (Val)SELECT C.ValFROM dbo.Cheap AS COPTION (MAXDOP 1);
Nem Sorban Cél
A következő lekérdezést úgy, hogy ugyanazt a sort minden asztalon, majd visszatér az összefűzés a két szett:
SELECT E.Val FROM dbo.Expensive AS E WHERE E.Val BETWEEN 751000 AND 751005 UNION ALL SELECT C.ValFROM dbo.Cheap AS C WHERE C.Val BETWEEN 751000 AND 751005;
A végrehajtási tervet készített, amelyet a lekérdezés-optimalizáló:
a figyelmeztetés a gyökér SELECT
Üzemeltető figyelmezteti minket, hogy a nyilvánvaló hiányzó index a halom asztalra. A táblázat szkennelési operátorának figyelmeztetését a Sentry One Plan Explorer adja hozzá. Felhívja a figyelmünket a vizsgálat során rejtett maradék predikátum I/O költségére.
a Konkatenáció bemeneteinek sorrendje itt nem számít, mert nem állítottunk be sorcélt. Mindkét bemenet teljesen olvasható lesz az összes eredménysor visszaadásához. Érdekes (bár ez nem garantált) észreveszi, hogy a bemenetek sorrendje az eredeti lekérdezés szöveges sorrendjét követi. Vegye figyelembe azt is, hogy a végeredmény sorainak sorrendje sem kerül meghatározásra, mivel nem használtunk felső szintű ORDER BY
záradékot. Feltételezzük, hogy ez szándékos, a végső megrendelés pedig lényegtelen a feladathoz.
ha megfordítjuk a lekérdezésben szereplő táblázatok írásbeli sorrendjét:
SELECT C.ValFROM dbo.Cheap AS C WHERE C.Val BETWEEN 751000 AND 751005 UNION ALL SELECT E.Val FROM dbo.Expensive AS E WHERE E.Val BETWEEN 751000 AND 751005;
A végrehajtási tervet követi a változás elérése a fürtözött táblázat első (ez megint csak nem garantált):
a két lekérdezések is várható, hogy ugyanaz a teljesítmény jellemzők, mint ők végezze el ugyanazokat a műveleteket, csak más sorrendben.
egy sor cél
nyilvánvaló, hogy az indexelés hiánya a halom asztalon általában bizonyos sorok megtalálását drágábbá teszi, összehasonlítva a fürtözött asztalon végzett ugyanazon művelettel. Ha megkérdezzük az optimalizáló egy terv, hogy visszatér az első sorban gyorsan elvárjuk SQL Server átrendezni az összefűzés bemenet, így az olcsó fürtözött táblázat a megkérdezett első.
a heap táblát először megemlítő lekérdezés használatával, valamint egy gyors 1 lekérdezési tipp segítségével adja meg a sor célját:
SELECT E.Val FROM dbo.Expensive AS E WHERE E.Val BETWEEN 751000 AND 751005 UNION ALL SELECT C.ValFROM dbo.Cheap AS C WHERE C.Val BETWEEN 751000 AND 751005OPTION (FAST 1);
A becsült végrehajtási tervet készített egy SQL Server 2008 R2:
Figyeljük meg, hogy az összefűzés bemenet más helyre került, hogy csökkentse a becsült költség az adatszolgáltató az első sorban. Vegye figyelembe azt is, hogy a hiányzó index és a maradék I/O figyelmeztetések eltűntek. Egyik kérdés sem következménye ennek a tervformának, amikor a cél az, hogy egy sort a lehető leggyorsabban visszaadjunk.
ugyanaz A lekérdezés ki az SQL Server 2016 (a számosság becslési modell) az, hogy:
SQL Server 2016 nem reordered az összefűzés bemenet. A Plan Explorer I/O figyelmeztetés visszatért, de sajnos az optimalizáló ezúttal nem készített hiányzó index figyelmeztetést (bár releváns).
Általános átrendezés
mint már említettük, az optimalizálás utáni újraírás, amely átrendezi a konkatenációs bemeneteket, csak a következőkre hatékony:
- SQL Server 2008 R2, illetve a korábbi
- Egy sor cél pontosan egy
Ha valóban csak egy sort vissza, ahelyett, hogy egy terv optimalizált vissza az első sorban gyorsan (de ami végső soron mindig vissza sor), használhatjuk a TOP
záradék a származtatott tábla vagy a közös asztal kifejezés (CTE):
SELECT TOP (1) UA.ValFROM( SELECT E.Val FROM dbo.Expensive AS E WHERE E.Val BETWEEN 751000 AND 751005 UNION ALL SELECT C.Val FROM dbo.Cheap AS C WHERE C.Val BETWEEN 751000 AND 751005) AS UA;
A SQL Server 2008 R2 vagy korábban, igy az optimális reordered-input terv:
SQL Server 2012, 2014, and 2016 no post-optimization átrendezés történik:
Ha szeretnénk több mint egy sor vissza, például aTOP (2)
, a kívánt újraírást nem kell alkalmazni az SQL Server 2008 R2 akkor is, ha a FAST 1
tipp is használható. Ebben a helyzetben olyan trükköket kell használnunk, mint például a TOP
változó és egy OPTIMIZE FOR
tipp:
DECLARE @TopRows bigint = 2; -- Number of rows actually needed SELECT TOP (@TopRows) UA.ValFROM( SELECT E.Val FROM dbo.Expensive AS E WHERE E.Val BETWEEN 751000 AND 751005 UNION ALL SELECT C.Val FROM dbo.Cheap AS C WHERE C.Val BETWEEN 751000 AND 751005) AS UAOPTION (OPTIMIZE FOR (@TopRows = 1)); -- Just a hint
a lekérdezési tipp elegendő egy sor céljának beállításához, míg a változó futási értéke biztosítja a kívánt sorok számát (2).
az SQL Server 2008 R2 tényleges végrehajtási terve a következő:
mindkét visszaadott sor az újrarendelt Keresési bemenetből származik, és a táblázat beolvasása egyáltalán nem kerül végrehajtásra. Plan Explorer mutatja a sor számít piros, mert a becslés volt egy sorban (miatt a célzást), míg a két sor találkozott futási időben.
UNION ALL nélkül
Ez a probléma nem korlátozódik a UNION ALL
– vel kifejezetten írt lekérdezésekre. Más konstrukciók, mint például a EXISTS
és OR
, szintén eredményezhetik az optimalizáló concatenation operátort, amely a bemeneti átrendezés hiányától szenvedhet. Volt egy friss kérdés adatbázis rendszergazdák Stack Exchange pontosan ezt a kérdést. Átalakítja a lekérdezés a kérdés, hogy használja a példa táblázatok:
SELECT CASE WHEN EXISTS ( SELECT 1 FROM dbo.Expensive AS E WHERE E.Val BETWEEN 751000 AND 751005 ) OR EXISTS ( SELECT 1 FROM dbo.Cheap AS C WHERE C.Val BETWEEN 751000 AND 751005 ) THEN 1 ELSE 0 END;
A végrehajtási tervet az SQL Server 2016 van a kupac táblázat az első bemenet:
A SQL Server 2008 R2 a rend a bemenet van optimalizálva, hogy az tükrözze a sorban cél a félig csatlakozni:
a több optimális terv, a halom vizsgálat nem is lehet végrehajtani.
Workarounds
bizonyos esetekben a lekérdezőíró számára nyilvánvaló lesz, hogy az egyik összefűzési bemenet mindig olcsóbb lesz a futtatáshoz, mint a többi. Ha ez igaz, akkor nagyon érvényes a lekérdezés átírása, hogy az olcsóbb összefűzési bemenetek először írásbeli sorrendben jelenjenek meg. Ez természetesen azt jelenti, hogy a lekérdező írónak tisztában kell lennie ezzel az optimalizáló korlátozással, és készen kell állnia arra, hogy dokumentálatlan viselkedésre támaszkodjon.
nehezebb kérdés merül fel, amikor a konkatenációs bemenetek költsége a körülményektől függ, talán a paraméterértékektől függően. Használata OPTION (RECOMPILE)
nem segít az SQL Server 2012 vagy újabb. Ez az opció segíthet az SQL Server 2008 R2 vagy korábbi, de csak akkor, ha az egysoros cél követelmény is teljesül.
Ha vannak aggodalmak támaszkodva megfigyelt viselkedés (lekérdezési terv összefűzés bemenetek megfelelő a lekérdezés szöveges rend) egy terv útmutató lehet használni, hogy a hatályos terv alakja. Ahol a különböző bemeneti megbízások optimálisak a különböző körülményekhez, több tervvezetőt lehet használni, ahol a feltételek előre pontosan kódolhatók. Ez azonban aligha ideális.
végső gondolatok
az SQL Server query optimizer valójában tartalmaz egy költségalapú feltárási szabályt, UNIAReorderInputs
, amely képes konkatenációs bemeneti rendelési variációk létrehozására és alternatívák feltárására a költségalapú optimalizálás során (nem egy lövés utáni optimalizálási újraírás).
Ez a szabály jelenleg nincs engedélyezve általános használatra. Amennyire meg tudom mondani, csak akkor aktiválódik, ha egy terv útmutató vagy USE PLAN
tipp van jelen. Ez lehetővé teszi, hogy a motor sikeresen erő egy terv, hogy keletkezett egy lekérdezést, amely alkalmas a bemenet-átrendezéséhez átírni, még akkor is, ha az aktuális lekérdezés nem jogosult.
az az érzésem, hogy ez a felfedezés szabály szándékosan korlátozódik erre a célra, mert lekérdezések, hogy előnyös lenne a összefűzés bemeneti átrendezéséhez részeként költség alapú optimalizálás megállapítható, hogy nem kellően gyakori, vagy talán azért, mert fennáll a veszély, hogy az extra erőfeszítés, nem fizeti ki. Saját véleményem az, hogy a Konkatenációs operátor bemeneti átrendezését mindig fel kell tárni, amikor egy sor célja van érvényben.
szégyen, hogy a (korlátozottabb) optimalizálás utáni újraírás nem hatékony az SQL Server 2012 vagy újabb verziójában. Ennek oka lehet, hogy egy finom hiba, de nem találtam semmit erről a dokumentációban, Tudásbázis, vagy a Connect. Itt hozzáadtam egy új csatlakozási elemet.
2017. augusztus 9. frissítése: ezt most a 4199-es nyomkövetési jel alatt rögzítik az SQL Server 2014 és 2016 esetében, lásd KB 4023419:
FIX: Az UNION ALL és a row goal lekérdezése lassabb lehet az SQL Server 2014 vagy újabb verziókban, ha összehasonlítjuk az SQL Server 2008 R2
Leave a Reply