sql >> Database >  >> RDS >> Database

Instellen en identificeren van rijdoelen in uitvoeringsplannen

Inleiding

De productdocumentatie van SQL Server is een beetje licht over het onderwerp rijdoelen . De belangrijkste officiële referenties zijn in:

  • Hints (Transact-SQL) - Query (FAST en DISABLE_OPTIMIZER_ROWGOAL hints)
  • DBCC TRACEON – Traceervlaggen (Transact-SQL) (traceervlag 4138)
  • Het kan lang duren voordat een query wordt uitgevoerd als de query-optimizer de operator Top (KB 2667211) gebruikt

Als mensen om meer informatie vragen dan er staat, verwijs ik ze normaal gesproken naar een of meer van de volgende:

  • Rijdoelen in actie door het SQL Server Query Optimization-team
  • Rijdoelen opnieuw bezocht – SNELLE hintbegeleiding ook door het SQL Server Query Optimization Team
  • Roy Goals Gone Rogue door Bart Duncan
  • In de Optimizer:rij doelen in de diepte door mij
  • De SSIS-afstemtip die iedereen mist van Rob Farley

Om het kort samen te vatten:Met de functie rijdoel kan de optimizer een uitvoeringsplan (of een deel van een uitvoeringsplan) genereren met als doel een bepaald aantal rijen snel terug te geven. Dit in tegenstelling tot het normale gedrag (zonder rijdoel), dat erop gericht is een plan te vinden dat is geoptimaliseerd voor de volledige potentiële resultatenset.

Een strategie voor rijdoelen houdt in het algemeen in dat niet-blokkerende navigatiebewerkingen (bijvoorbeeld geneste loops-joins, indexzoekopdrachten en opzoekacties) worden bevoordeeld boven blokkerende, set-gebaseerde bewerkingen zoals sorteren en hashen. Dit kan handig zijn wanneer de klant kan profiteren van een snelle start en een gestage stroom van rijen (met misschien een langere algehele uitvoeringstijd - zie het bericht van Rob Farley hierboven). Er zijn ook de meer voor de hand liggende en traditionele toepassingen, b.v. bij het presenteren van resultaten pagina voor pagina.

Natuurlijk is er een risico-element verbonden aan een rijdoelenplan. Als alles in grote lijnen verloopt zoals de optimizer verwacht (gezien de beschikbare informatie en de gemaakte modelaannames), zal het uitvoeringsplan het gevraagde aantal rijen sneller en efficiënter streamen dan het geval zou zijn geweest zonder het rijdoel.

Helaas, wanneer de rijdoelstrategie fout gaat, kan dit een prestatieramp zijn (zie de post van Bart Duncan). Dit kan bijvoorbeeld gebeuren wanneer de optimizer onvolledige informatie heeft, een ongunstige gegevensverdeling tegenkomt of een onveilige aanname doet. In ieder geval is de oorzaak van de slechte prestaties bijna altijd dat er veel meer rijen moeten worden verwerkt op het moment van uitvoering dan de optimizer had verwacht.

Het kan erg handig zijn om uitvoeringsplangebieden te identificeren die worden beïnvloed door een rijdoel, omdat het ons helpt te begrijpen waarom de optimizer heeft de keuzes gemaakt die het heeft gemaakt. Dit is met name belangrijk wanneer de logica van het rijdoel een ongunstige uitkomst oplevert. Zonder de rol van het rijdoel te begrijpen, kan het lijken alsof de optimizer het aantal rijen simpelweg heeft onderschat, waardoor mensen op de verkeerde plaatsen (bijvoorbeeld statistieken) naar een hoofdoorzaak gaan zoeken.

Rijdoelen instellen

Het is een stuk gemakkelijker om naar rijdoeleffecten te zoeken als men weet wat voor soort dingen er in de eerste plaats voor kunnen zorgen dat een rijdoel wordt ingesteld. In de officiële documentatie wordt vaak gesproken over rijdoelen die worden geassocieerd met de zoekwoorden TOP , FAST , IN , en EXISTS . Hierdoor kan de lezer een onvolledig of misleidend begrip krijgen, dus het is de moeite waard even de tijd te nemen om enkele aspecten te verduidelijken.

Ik wil meteen benadrukken dat het gebruik van specifieke T-SQL-zoekwoorden in een zoekopdracht garandeert niet dat er een rijdoel wordt ingesteld . De officiële documentatie vermeldt bepaalde trefwoorden om mensen te helpen bij het identificeren van veelvoorkomende scenario's waarin rijdoelen mogelijk worden geïntroduceerd, zonder al te veel technische details.

Een tweede algemeen punt om in gedachten te houden is dat een rijdoel alleen wordt ingesteld als het doel lager zou zijn dan de normale schatting . Het heeft immers niet veel zin om een ​​planfragment te genereren dat is geoptimaliseerd voor 100 rijen als het geheel naar verwachting toch maar 50 rijen zal produceren. Voor de duidelijkheid:dit punt is altijd van toepassing op alle manieren waarop een rijdoel kan worden ingesteld. Als u een rijdoel verwacht, maar er geen ziet, is dit een waarschijnlijke oorzaak.

Ten slotte, voor de preambule, merk op dat rijdoelen een op kosten gebaseerde optimalisatie zijn; een rijdoel heeft invloed op de optimalisatiekeuzes, dus als er geen keuzes hoeven te worden gemaakt (d.w.z. een triviaal plan), is er geen rijdoeleffect.

Laten we nu kijken naar de dingen die een rijdoel kunnen stellen:

SNEL en TOP

De FAST gebruiken queryhint is een betrouwbare manier om een ​​rijdoel in te stellen op de root van het uitvoeringsplan (behoudens de hierboven vermelde algemene uitzonderingen). A SET ROWCOUNT n statement stelt ook een vergelijkbaar rijdoel op het hoogste niveau in (wanneer n is natuurlijk niet nul) voor de uitspraken waarop het van toepassing is.

Een TOP schrijven clausule in een query resulteert ook heel vaak in een rijdoel. Zolang het voltooide uitvoeringsplan een fysieke Top-operator bevat, is het waarschijnlijk dat ten minste een deel van het plan onder de Top-operator werd beïnvloed door een rijdoel (wederom zijn de algemene voorwaarden van toepassing).

Merk op dat Top-operators geïntroduceerd door de query-optimizer (zonder een door een zoekopdracht gespecificeerde TOP clausule) kan ook een rijdoel instellen. Dit is belangrijk, want er zijn allerlei manieren waarop dit kan gebeuren, bijvoorbeeld bij het filteren op een eenvoudig rijnummer, zoals blijkt uit de volgende AdventureWorks-query:

SELECT
    THN.RowNum,
    THN.TransactionID 
FROM 
(
    SELECT 
        TH.TransactionID, 
        RowNum = 
            ROW_NUMBER() OVER (
                ORDER BY TH.TransactionID ASC)
    FROM Production.TransactionHistory AS TH
    WHERE
        TH.ProductID = 400
) AS THN
WHERE
    THN.RowNum >= 10
    AND THN.RowNum < 20
ORDER BY
    THN.RowNum ASC;

Het uitvoeringsplan voor die query bevat een Top-operator die door de optimizer is toegevoegd (om het aantal verwerkte rijen te beperken tot 20):