sql >> Databasteknik >  >> RDS >> Database

StarJoinInfo i utförandeplaner

Då och då kanske du märker att en eller flera anslutningar i en exekveringsplan är kommenterade med en StarJoinInfo strukturera. Det officiella showplan-schemat har följande att säga om detta planelement (klicka för att förstora):

Den direktanslutna dokumentationen som visas där ("ytterligare information om Star Join-strukturen ") är inte så upplysande, även om de andra detaljerna är ganska spännande – vi kommer att titta på dessa i detalj.

Om du konsulterar din favoritsökmotor för mer information med hjälp av termer som "SQL Server star join optimization", kommer du sannolikt att se resultat som beskriver optimerade bitmappsfilter. Detta är en separat Enterprise-only-funktion som introduceras i SQL Server 2008 och inte relaterad till StarJoinInfo struktur överhuvudtaget.

Optimeringar för selektiva stjärnfrågor

Förekomsten av StarJoinInfo indikerar att SQL Server tillämpade en av en uppsättning optimeringar som är inriktade på selektiva stjärnschema-frågor. Dessa optimeringar är tillgängliga från SQL Server 2005, i alla utgåvor (inte bara Enterprise). Observera att selektiv här hänvisar till antalet rader som hämtas från faktatabellen. Kombinationen av dimensionella predikat i en fråga kan fortfarande vara selektiv även när dess individuella predikat kvalificerar ett stort antal rader.

Vanlig indexkorsning

Frågeoptimeraren kan överväga att kombinera flera icke-klustrade index där ett lämpligt enda index inte finns, vilket följande AdventureWorks-fråga visar:

SELECT COUNT_BIG(*)
FROM Sales.SalesOrderHeader
WHERE SalesPersonID = 276
AND CustomerID = 29522;

Optimeraren avgör att kombinera två icke-klustrade index (ett på SalesPersonID och den andra på CustomerID ) är det billigaste sättet att tillfredsställa denna fråga (det finns inget index på båda kolumnerna):

Varje indexsökning returnerar den klustrade indexnyckeln för rader som passerar predikatet. Sammanfogningen matchar de returnerade nycklarna för att säkerställa att endast rader som matchar båda predikat förs vidare.

Om tabellen var en hög skulle varje sökning returnera högradidentifierare (RID) istället för klustrade indexnycklar, men den övergripande strategin är densamma:hitta radidentifierare för varje predikat och matcha dem sedan.

Manuell Star Join Index Intersection

Samma idé kan utökas till frågor som väljer rader från en faktatabell med hjälp av predikat som tillämpas på dimensionstabeller. För att se hur detta fungerar, överväg följande fråga (med hjälp av Contoso BI-exempeldatabasen) för att hitta det totala försäljningsbeloppet för MP3-spelare som säljs i Contoso-butiker med exakt 50 anställda:

SELECT
    SUM(FS.SalesAmount)
FROM dbo.FactSales AS FS
JOIN dbo.DimProduct AS DP
    ON DP.ProductKey = FS.ProductKey
JOIN dbo.DimStore AS DS
    ON DS.StoreKey = FS.StoreKey
WHERE
    DS.EmployeeCount = 50
    AND DP.ProductName LIKE N'%MP3%';

För jämförelse med senare försök, producerar denna (mycket selektiva) fråga en frågeplan som följande (klicka för att expandera):

Den utförandeplanen har en beräknad kostnad på drygt 15,6 enheter . Den har parallell körning med en fullständig genomsökning av faktatabellen (om än med ett bitmappsfilter tillämpat).

Faktatabellerna i denna exempeldatabas inkluderar inte som standard icke-klustrade index på faktatabellens främmande nycklar, så vi måste lägga till ett par:

CREATE INDEX ix_ProductKey ON dbo.FactSales (ProductKey);
CREATE INDEX ix_StoreKey ON dbo.FactSales (StoreKey);

Med dessa index på plats kan vi börja se hur indexskärning kan användas för att förbättra effektiviteten. Det första steget är att hitta identifierare för faktatabellrader för varje separat predikat. Följande frågor tillämpar ett enstaka dimensionspredikat och går sedan tillbaka till faktatabellen för att hitta radidentifierare (faktatabellklustrade indexnycklar):

-- Product dimension predicate
SELECT FS.SalesKey
FROM dbo.FactSales AS FS
JOIN dbo.DimProduct AS DP
    ON DP.ProductKey = FS.ProductKey
WHERE DP.ProductName LIKE N'%MP3%';
 
-- Store dimension predicate
SELECT FS.SalesKey
FROM dbo.FactSales AS FS
JOIN dbo.DimStore AS DS
    ON DS.StoreKey = FS.StoreKey
WHERE DS.EmployeeCount = 50;

Frågeplanerna visar en genomsökning av tabellen med små dimensioner, följt av uppslagningar med hjälp av faktatabellens icke-klustrade index för att hitta radidentifierare (kom ihåg att icke-klustrade index alltid inkluderar bastabellens klustringsnyckel eller heap RID):

Skärningspunkten mellan dessa två uppsättningar av faktatabellklustrade indexnycklar identifierar raderna som ska returneras av den ursprungliga frågan. När vi har dessa radidentifierare behöver vi bara slå upp försäljningsbeloppet i varje faktatabellsrad och beräkna summan.

Manuell Index Intersection Query

Att sätta ihop allt detta i en fråga ger följande:

SELECT SUM(FS.SalesAmount)
FROM
(
    SELECT FS.SalesKey
    FROM dbo.FactSales AS FS
    JOIN dbo.DimProduct AS DP
        ON DP.ProductKey = FS.ProductKey
    WHERE DP.ProductName LIKE N'%MP3%'
    INTERSECT
    -- Store dimension predicate
    SELECT FS.SalesKey
    FROM dbo.FactSales AS FS
    JOIN dbo.DimStore AS DS
        ON DS.StoreKey = FS.StoreKey
    WHERE DS.EmployeeCount = 50
) AS Keys
JOIN dbo.FactSales AS FS WITH (FORCESEEK)
    ON FS.SalesKey = Keys.SalesKey
OPTION (MAXDOP 1);

FORCESEEK ledtråd finns för att säkerställa att vi får punktuppslag till faktatabellen. Utan detta väljer optimeraren att skanna faktatabellen, vilket är precis vad vi är ute efter att undvika. MAXDOP 1 tips hjälper bara till att hålla den slutliga planen till en ganska rimlig storlek för visningsändamål (klicka för att se den i full storlek):

Komponenterna i den manuella indexkorsningsplanen är ganska lätta att identifiera. De två icke-klustrade faktatabellernas indexuppslagningar på höger sida producerar de två uppsättningarna av faktatabellradidentifierare. Hash-kopplingen hittar skärningspunkten mellan dessa två uppsättningar. Den klustrade indexsökningen i faktatabellen hittar försäljningsbeloppen för dessa radidentifierare. Slutligen beräknar Stream Aggregate det totala beloppet.

Den här frågeplanen gör relativt få sökningar i faktatabellen icke-klustrade och klustrade index. Om frågan är tillräckligt selektiv kan detta mycket väl vara en billigare exekveringsstrategi än att skanna faktatabellen helt. Contoso BI-exempeldatabasen är relativt liten, med endast 3,4 miljoner rader i försäljningsfaktatabellen. För större faktatabeller kan skillnaden mellan en fullständig genomsökning och några hundra uppslag vara mycket betydande. Tyvärr introducerar den manuella omskrivningen några allvarliga kardinalitetsfel, vilket resulterar i en plan med en uppskattad kostnad på 46,5 enheter .

Automatisk Star Join Index Intersection with Lookups

Lyckligtvis behöver vi inte bestämma om frågan vi skriver är tillräckligt selektiv för att motivera denna manuella omskrivning. Stjärnanslutningsoptimeringarna för selektiva frågor innebär att frågeoptimeraren kan utforska det här alternativet åt oss med hjälp av den mer användarvänliga ursprungliga frågesyntaxen:

SELECT
    SUM(FS.SalesAmount)
FROM dbo.FactSales AS FS
JOIN dbo.DimProduct AS DP
    ON DP.ProductKey = FS.ProductKey
JOIN dbo.DimStore AS DS
    ON DS.StoreKey = FS.StoreKey
WHERE
    DS.EmployeeCount = 50
    AND DP.ProductName LIKE N'%MP3%';

Optimeraren producerar följande exekveringsplan med en uppskattad kostnad på 1,64 enheter (klicka för att förstora):

Skillnaderna mellan denna plan och den manuella versionen är:indexkorsningen är en inre sammanfogning istället för en semi-fog; och den klustrade indexsökningen visas som en nyckelsökning istället för en klustrad indexsökning. Om faktatabellen vore en hög, skulle nyckeluppslagningen vara en RID-uppslagning, med risk för att det skulle vara svårt.

StarJoinInfo-egenskaperna

Joinerna i denna plan har alla en StarJoinInfo strukturera. För att se det, klicka på en join-iterator och titta i fönstret SSMS-egenskaper. Klicka på pilen till vänster om StarJoinInfo element för att expandera noden.

Den icke-klustrade faktatabellen ansluter till höger om planen är Index Lookups byggda av optimeraren:

Hash-join har en StarJoinInfo struktur som visar att den utför en Index Intersection (återigen, tillverkad av optimeraren):

StarJoinInfo för kopplingen längst till vänster om Nested Loops visar att den genererades för att hämta faktatabellsrader efter radidentifierare. Det är i roten av det optimeringsgenererade stjärnanslutningsunderträdet:

Kartesiska produkter och indexsökning med flera kolumner

Indexkorsningsplanerna som betraktas som en del av stjärnanslutningsoptimeringarna är användbara för selektiva faktatabellsfrågor där enkolumns icke-klustrade index finns på faktatabellens främmande nycklar (en vanlig designpraxis).

Ibland är det också meningsfullt att skapa index med flera kolumner på främmande nycklar för faktatabeller, för ofta frågade kombinationer. De inbyggda selektiva stjärnfrågeoptimeringarna innehåller också en omskrivning för detta scenario. För att se hur detta fungerar, lägg till följande flerkolumnindex i faktatabellen:

CREATE INDEX ix_ProductKey_StoreKey 
ON dbo.FactSales (ProductKey, StoreKey);

Kompilera testfrågan igen:

SELECT
    SUM(FS.SalesAmount)
FROM dbo.FactSales AS FS
JOIN dbo.DimProduct AS DP
    ON DP.ProductKey = FS.ProductKey
JOIN dbo.DimStore AS DS
    ON DS.StoreKey = FS.StoreKey
WHERE
    DS.EmployeeCount = 50
    AND DP.ProductName LIKE N'%MP3%';

Frågeplanen har inte längre indexkorsning (klicka för att förstora):

Strategin som väljs här är att tillämpa varje predikat på dimensionstabellerna, ta den kartesiska produkten av resultaten och använda den för att söka in i båda nycklarna i flerkolumnindexet. Frågeplanen utför sedan en nyckelsökning i faktatabellen med hjälp av radidentifierare exakt som tidigare.

Frågeplanen är särskilt intressant eftersom den kombinerar tre funktioner som ofta betraktas som dåliga saker (fullständiga skanningar, kartesiska produkter och nyckelsökningar) i en prestandaoptimering . Detta är en giltig strategi när produkten av de två dimensionerna förväntas vara mycket liten.

Det finns ingen StarJoinInfo för den kartesiska produkten, men de andra kopplingarna har information (klicka för att förstora):

Indexfilter

Med hänvisning till showplan-schemat finns det en annan StarJoinInfo operation vi behöver täcka:

Index Filter värde ses med kopplingar som anses vara tillräckligt selektiva för att vara värda att utföra innan faktatabellens hämtning. Joins som inte är tillräckligt selektiva kommer att utföras efter hämtningen och kommer inte att ha en StarJoinInfo struktur.

För att se ett indexfilter med vår testfråga måste vi lägga till en tredje sammanfogningstabell till mixen, ta bort de icke-klustrade faktatabellindexen som skapats hittills och lägga till en ny:

CREATE INDEX ix_ProductKey_StoreKey_PromotionKey
ON dbo.FactSales (ProductKey, StoreKey, PromotionKey);
 
SELECT
    SUM(FS.SalesAmount)
FROM dbo.FactSales AS FS
JOIN dbo.DimProduct AS DP
    ON DP.ProductKey = FS.ProductKey
JOIN dbo.DimStore AS DS
    ON DS.StoreKey = FS.StoreKey
JOIN dbo.DimPromotion AS DPR 
    ON DPR.PromotionKey = FS.PromotionKey
WHERE
    DS.EmployeeCount = 50
    AND DP.ProductName LIKE N'%MP3%'
    AND DPR.DiscountPercent <= 0.1;

Frågeplanen är nu (klicka för att förstora):

En Heap Index Intersection Query Plan

För fullständighetens skull är här ett skript för att skapa en högkopia av faktatabellen med de två icke-klustrade index som behövs för att möjliggöra omskrivning av indexkorsningsoptimeraren:

SELECT * INTO FS FROM dbo.FactSales;
 
CREATE INDEX i1 ON dbo.FS (ProductKey);
CREATE INDEX i2 ON dbo.FS (StoreKey);
 
SELECT SUM(FS.SalesAmount)
FROM FS AS FS
JOIN dbo.DimProduct AS DP
    ON DP.ProductKey = FS.ProductKey
JOIN dbo.DimStore AS DS
    ON DS.StoreKey = FS.StoreKey
WHERE DS.EmployeeCount <= 10
AND DP.ProductName LIKE N'%MP3%';

Exekveringsplanen för den här frågan har samma funktioner som tidigare, men indexskärningen utförs med RID istället för faktatabellsklustrade indexnycklar, och den sista hämtningen är en RID Lookup (klicka för att expandera):

Sluta tankar

Optimeringsomskrivningarna som visas här är inriktade på frågor som returnerar ett relativt litet antal rader från en stor faktatabell. Dessa omskrivningar har varit tillgängliga i alla utgåvor av SQL Server sedan 2005.

Även om den är avsedd att påskynda selektiva stjärn- (och snöflinga)-schemafrågor i datalagring, kan optimeraren tillämpa dessa tekniker varhelst den upptäcker en lämplig uppsättning tabeller och kopplingar. Heuristiken som används för att upptäcka stjärnfrågor är ganska bred, så du kan stöta på planformer med StarJoinInfo strukturer i nästan vilken typ av databas som helst. Alla tabeller av rimlig storlek (säg 100 sidor eller mer) med referenser till mindre (dimensionsliknande) tabeller är en potentiell kandidat för dessa optimeringar (observera att explicita främmande nycklar är inte krävs).

För er som gillar sådana saker kallas optimerarregeln som är ansvarig för att generera selektiva stjärnkopplingsmönster från en logisk n-tabellkoppling StarJoinToIdxStrategy (stjärnanslutning till indexstrategi).


  1. Hur infogar/uppdaterar man större data i Oracle-tabellerna?

  2. Dålig praxis i databasdesign

  3. Hur man duplicerar tabell i MySQL

  4. MySQL-konverteringsfunktion