sql >> Databasteknik >  >> RDS >> Sqlserver

SQL Server Interns:Problematiska operatörer Pt. I – Skanningar

SQL Server har funnits i över 30 år och jag har arbetat med SQL Server nästan lika länge. Kalen täcker genomsökningar i del ett av SQL Server Internals:Problematic Operators.

Jag har sett många förändringar under åren (och decennier!) och versioner av denna otroliga produkt. I dessa inlägg kommer jag att dela med mig av hur jag ser på några av funktionerna eller aspekterna av SQL Server, ibland tillsammans med lite historiskt perspektiv.

Att justera dina SQL Server-frågor är en av de bästa sakerna du kan göra för bättre prestanda och optimering av SQL-serverdiagnostik. Men trimning är ett stort ämne! Att veta exakt hur man ställer in på bästa möjliga sätt kräver inte bara en grundlig kunskap om din data och din arbetsbelastning, utan kunskap om hur SQL Server faktiskt gör sina val av planexekvering. Så vad kan du göra om du inte är expert på SQL Server Internals? En sak du kan göra är att lita på personer som är experter, såväl som verktyg skrivna av experter. Verktyg som Quest Spotlight Cloud Tuning Pack kan ge dig några bra förslag för att komma igång på vägen mot bättre frågeprestanda. Naturligtvis känner inget externt verktyg till dina data och alla detaljer om alla dina arbetsbelastningar, så noggrann testning av alla förslag du bestämmer dig för att implementera rekommenderas alltid.

I dessa inlägg om problematiska operatörer kommer jag att anta att du har en del grundläggande kunskaper om SQL Server-indexstrukturer. Här är lite information som kan vara till hjälp:

  • En tabell utan ett klustrat index kallas en heap och har ingen ordning. Det finns ingen första eller sista raden. En hög är bara ett gäng rader i ingen speciell ordning.
  • Lövnivån för ett klustrat index är själva tabellen. (Det är inte en kopia av tabellen, det ÄR tabellen.) Raderna i indexet är logiskt ordnade efter vilken kolumn som än definierades som den klustrade indexnyckeln.
  • Lövnivån för ett icke-klustrat index innehåller en indexrad för varje rad i tabellen. Raderna innehåller de icke-klustrade nyckelkolumnerna och är logiskt ordnade i den ordning som nycklarna anges. Förutom nyckelkolumnerna innehåller de icke-klustrade indexraderna ett "bokmärke" som pekar på den refererade raden i tabellen. Bokmärket kan ha en av två former:
    1. Om tabellen har ett klustrat index är bokmärket den klustrade indexnyckeln. (Om den klustrade indexnyckeln är en del av den icke-klustrade indexnyckeln, kommer den inte att dupliceras.)
    2. Om tabellen är en hög är bokmärket ett rad-ID, eller RID, som anger den fysiska platsen för raden. Platsen anges vanligtvis som FileNum:PageNum:RowNum .

SQL Servers egna verktyg ger flera sätt att se den frågeexekveringsplan som optimeraren bestämde sig för att använda för en viss fråga. Med tillägget av Quest Spotlight Tuning Pack kan du få ännu mer information om dina planer.

Följande kod skapar kopior av två tabeller i AdventureWorks databas (jag använder AdventureWorks2016 , men du kan använda en annan version).

USE AdventureWorks2016;

GO

DROP TABLE IF EXISTS SalesHeader;

GO

SELECT *

INTO SalesHeader

FROM Sales.SalesOrderHeader;

GO

DROP TABLE IF EXISTS SalesDetail;

GO

SELECT * INTO SalesDetail

FROM Sales.SalesOrderDetail;

GO

Kör nu en fråga som sammanfogar de två tabellerna efter att ha aktiverat "Inkludera faktisk utförandeplan"

SELECT h.SalesOrderID, OrderDate, ProductID, UnitPrice, OrderQty

FROM SalesHeader h JOIN SalesDetail d

ON h.SalesOrderID = d.SalesOrderID

WHERE SalesOrderDetailID < 100;

GO

Quest Spotlight Tuning Pack kommer att rapportera ett problem med frågan, så du kan klicka på "Visa analys" och välja alternativet "Execution Plan". Du bör se följande:

Förstå tabellskanningar

Först vill jag gå ut och säga att det inte finns någon planoperatör som alltid är dålig! Varför skulle optimeraren lägga till den i din frågeplan om den var dålig? Det kan tyda på att det finns utrymme för förbättringar i dina data eller indexstrukturer, men i sig är det inte dåligt.

I exemplet ovan verkar Tuning Pack belysa tabellskanningarna, vilket indikerar att de kan vara problematiska. Men det är inte alltid sant att tabellskanningar är problematiska. En mycket värre situation skulle vara att använda en icke-klustrad indexsökning för en fråga som kommer åt varje rad i tabellen. För den här specifika frågan håller jag med om att skanningen kanske inte är bra eftersom vi bara är intresserade av ett fåtal rader i SalesDetail tabell (99 av 121 317 rader, eller mindre än en tiondels procent.)

Så vi kan titta på förslagen i analysrutan för att bygga index. Förslaget för SalesDetail tabellen är att bygga ett icke-klustrat index på SalesOrderID kolumnen (kolumnen i JOIN-satsen) och INKLUDERA varannan kolumn i tabellen som returneras av frågan. Förslaget för SalesHeader tabellen är ett icke-klustrat index på SalesOrderDetailId kolumn, som är kolumnen i WHERE-satsen, och INKLUDERA OrderDate kolumn, vilket är den enda andra kolumnen som returneras från den här tabellen.

Tänk om vår fråga var något annorlunda? Tänk om jag hade kört den här frågan med SELECT * istället för en specifik kolumnlista. Om du provar det och tittar på rekommendationerna föreslår det att du använder INCLUDE för varje kolumn i tabellen förutom kolumnen med en nyckel. Även om ett sådant index kan få just den här frågan att köras lite snabbare, kan det sluta med att andra frågor saktar ner, i synnerhet dina UPPDATERINGSfrågor. Detta index är i princip bara en kopia av tabellen, eftersom bladnivån i indexet kommer att innehålla varje kolumn i tabellen. Om du ser sådana rekommendationer som föreslår ett index som inkluderar alla kolumner i tabellen, rekommenderar jag definitivt att du går tillbaka lite och inte skapar det blint.

Frågejustering för din SQL-serverdiagnostik innebär inte bara att hantera index, utan också att hantera frågorna själva. För just den här frågan kan vi faktiskt vara bättre att skriva om frågan så att den INTE använder SELECT * för att returnera varje rad i tabellen. Att endast returnera en liten delmängd av kolumnerna kan vara tillräckligt, och då skulle ett mycket smalare index räcka, som i det första exemplet.

Skulle något av dessa index verkligen vara ett bra index att skapa? Det smalare indexet blir totalt sett mindre och kommer att påverkas mindre av uppdateringar av data. Ett index på alla kolumner är som en andra kopia av tabellen, sorterad i en annan ordning än själva tabellen. Det finns situationer där det kan vara användbart att ha en "andra kopia" av tabellen i en annan ordning, men det kommer att finnas mycket omkostnader för datamodifieringsoperationer. Det enda sättet att veta säkert det är att prova rekommendationerna på ett testsystem med en representativ arbetsbelastning. Det är bara du som känner till din data och dina frågor, så prova och se!

Förstå indexsökningar

Som jag nämnde ovan är tabellskanningar inte alltid en dålig sak. Men hur är det med indexskanningar? Eftersom en klustrad indexbladsnivå är själva tabellen, är en klustrad indexavsökning detsamma som en tabellskanning! om en tabellskanning är dålig är en klustrad indexskanning lika dålig. Men det är inte alltid dåligt. Återigen måste du testa det på ditt system.

Rekommendationerna från SQL Server Engine som Quest Spotlight Tuning Pack visar att du aldrig föreslår ett klustrat index. det kan föreslå en icke-klustrad som inkluderar varje kolumn i tabellen (som nämnts tidigare), vilket bara är en dubblett av tabellen. Att ta reda på den eller de bästa kolumnerna för ditt klustrade index är ett stort ämne i sig, så jag går inte in på det här.

Vad är en sökning? En sökoperation i en plan betyder att SQL Server använder den ordnade informationen i indexträdet för att hitta en rad, en uppsättning rader eller start- och/eller stopppunkten i ett radintervall. I allmänhet är det en helt rimlig operation att använda en icke-klustrad indexsökning om du bara returnerar en mycket liten andel rader från en tabell. Men en sökning är inte ett bra val för en fråga som returnerar MÅNGA rader från en tabell. Hur många är LOTS? Det finns inget enkelt svar men om din fråga returnerar mer än några få procent av raderna bör du se till att du testar indexförslagen noggrant. Ibland är en tabellsökning, eller klustrad indexsökning, bättre än en indexsökning. (För ett sådant exempel, se mitt blogginlägg här).

Verktyg som Quest Spotlight Tuning Pack kan ge dig bra förslag för att komma igång på din inställningsresa med SQL-serverdiagnostik, men ju mer du vet om hur SQL Server-index och SQL Server-optimeraren fungerar, desto bättre kommer du att kunna utvärdera dessa förslag för dina frågor och din data, och eventuellt till och med komma med egna förslag.

I följande inlägg i den här serien kommer jag att berätta om andra problematiska operatörer som kan dyka upp i dina frågeplaner, så kom tillbaka snart!


  1. Se om en tabell har en DEFAULT-begränsning i SQL Server med OBJECTPROPERTY()

  2. Matcha utbud med efterfrågan – lösningar, del 3

  3. Returnera partitionsnumret för varje rad när du frågar efter en partitionerad tabell i SQL Server (T-SQL)

  4. Är det nödvändigt att kassera DbCommand efter användning?