sql >> Database >  >> RDS >> Database

GEBRUIK HINT en DISABLE_OPTIMIZED_NESTED_LOOP

Een van de beschikbare algoritmen om twee tabellen samen te voegen in SQL Server is Nested Loops. De geneste loops-join gebruikt één join-invoer als de buitenste invoertabel en één als de binnenste invoertabel. De buitenste lus herhaalt de buitenste invoertabel rij voor rij. De binnenste lus, uitgevoerd voor elke buitenste rij, zoekt naar overeenkomende rijen in de binnenste invoertabel.

Dit wordt een naïeve geneste loops-join genoemd.

Als u een index op join-voorwaarden in de binnenste invoertabel hebt, is het niet nodig om voor elke rij van de buitenste tabel een binnenlus uit te voeren. In plaats daarvan kunt u de waarde van de externe tabel als zoekargument doorgeven en alle geretourneerde rijen van de binnenste tabel verbinden met de rijen van de buitenste tabel.

Het zoeken door de binnenste tabel is een willekeurige toegang. De SQL Server, vanaf versie 2005, heeft de batch-sorteeroptimalisatie (niet verwarren met de Sort-operator in Batch-modus voor Columnstore-indexen). Het doel van de optimalisatie is om zoeksleutels uit de externe tabel te bestellen voordat gegevens uit de interne tabel worden opgehaald. Een willekeurige toegang zal dus sequentieel zijn.

Het uitvoeringsplan geeft de batchsorteerbewerking niet als een afzonderlijke operator weer. In plaats daarvan kunt u de eigenschap Optimized=true zien in de operator Geneste lussen. Als het mogelijk zou zijn om batchsortering als een aparte operator in het plan te zien, zou het er als volgt uitzien:

In dit pseudo-plan lezen we gegevens uit de niet-geclusterde ix_CustomerID-index in de volgorde van deze CustomerID-indexsleutel. Vervolgens moeten we Key Lookup in de geclusterde index uitvoeren, aangezien ix_CustomerID geen dekkende index is. Key Lookup is een zoekbewerking met geclusterde indexsleutels - een willekeurige toegang. Om het sequentieel te maken, kan SQL Server batchsortering uitvoeren op de geclusterde indexsleutel.

Raadpleeg mijn artikel Batchsortering en geneste lussen voor meer informatie over batchsortering.

Deze optimalisatie geeft een mooie boost met voldoende rijen. U kunt meer lezen over de testresultaten in de blog OPTIMIZED Nested Loops Joins, gemaakt door Craig Freedman, een ontwikkelaar van optimalisatieprogramma's.

Als het werkelijke aantal rijen echter kleiner is dan verwacht, kunnen de extra kosten van de CPU om dit soort te bouwen de voordelen ervan verbergen, het CPU-verbruik verhogen en de prestaties verminderen.

Beschouw dit specifieke voorbeeld:

use tempdb;
go
-- create a test table (SalesOrderID - clustered PK)
create table dbo.SalesOrder(SalesOrderID int identity primary key, CustomerID int not null, SomeData char(200) not null);
go
-- add test data
with n as (select top(1000000) rn = row_number() over(order by (select null)) from sys.all_columns c1,sys.all_columns c2)
insert dbo.SalesOrder(CustomerID, SomeData) select rn%500000, str(rn,100) from n;
-- create a clustered index
create index ix_c on dbo.Salesorder(CustomerID);
go
-- the batch sort optimization is enabled by default (Nested Loops: Optimized = true)
select * from dbo.SalesOrder with(index(ix_c)) where CustomerID < 1000;
-- disable it with the DISABLE_OPTIMIZED_NESTED_LOOP hint (Nested Loops: Optimized = false)
select * from dbo.SalesOrder with(index(ix_c)) where CustomerID < 1000 option(use hint('DISABLE_OPTIMIZED_NESTED_LOOP'));
go

Het geretourneerde resultaat:

Ik wil uw aandacht vestigen op de verschillende volgorde van rijen in de uitvoer. De server retourneert rijen in de volgorde waarin ze worden verwerkt, omdat we ORDER BY niet expliciet hebben opgegeven. In het eerste geval lezen we geleidelijk af van de ix_c index. Om willekeurige metingen van de geclusterde index te optimaliseren, filteren we rijen echter op de geclusterde SalesOrderID-indexsleutel. In het tweede geval is er geen sortering en worden de reads gedaan in de CustomerID-sleutelvolgorde van de niet-geclusterde index ix_c.

Verschil met de 2340-traceervlag

Ondanks het feit dat de documentatie de traceringsvlag 2340 specificeert als een equivalent van de DISABLE_OPTIMIZED_NESTED_LOOP hint, is het niet echt waar.

Beschouw het volgende voorbeeld waar ik de UPDATE STATISTICS … WITH PAGECOUNT ongedocumenteerde opdracht zal gebruiken om de optimizer te misleiden door te zeggen dat de tabel meer pagina's in beslag neemt dan hij in werkelijkheid heeft. Bekijk dan deze vragen:

  1. Zonder enige hints (ik heb MAXDOP toegevoegd om een ​​eenvoudig plan te behouden);
  2. Met de DISABLE_OPTIMIZED_NESTED_LOOP hint;
  3. Met de traceervlag 2340.
-- create a huge table
update statistics dbo.SalesOrder with pagecount = 100000;
go
set showplan_xml on;
go
-- 1. without hints
select * from dbo.SalesOrder with(index(ix_c)) where CustomerID < 1000000 option(maxdop 1);
-- 2. hint
select * from dbo.SalesOrder with(index(ix_c)) where CustomerID < 1000000 option(use hint('DISABLE_OPTIMIZED_NESTED_LOOP'), maxdop 1);
-- 3. trace flag
select * from dbo.SalesOrder with(index(ix_c)) where CustomerID < 1000000 option(querytraceon 2340, maxdop 1);
go
set showplan_xml off;
go

Als gevolg hiervan hebben we de volgende plannen:

Geneste lussen heeft de eigenschap Optimized =false in alle drie de plannen. Het feit is dat door de tabelbreedte te vergroten, we ook de kosten voor gegevenstoegang verhogen. Als de kosten hoog genoeg zijn, kan SQL Server de expliciete sorteeroperator gebruiken in plaats van de impliciete batchsorteeroperator. We kunnen dit zien in het eerste queryplan.

In de tweede query hebben we de hint DISABLE_OPTIMIZED_NESTED_LOOP gebruikt die de impliciete batchsortering uitschakelt. Het verwijdert echter een expliciete sortering door een afzonderlijke operator.

In het derde plan kunnen we zien dat ondanks het toevoegen van de traceringsvlag 2340, de sorteeroperator bestaat.

Het verschil tussen de hint en de vlag is dus als volgt:een hint schakelt de optimalisatie uit door een willekeurige toegang om te zetten in een seriële, afhankelijk van het feit of de server deze implementeert met de impliciete batchsortering of met de afzonderlijke sorteeroperator.

PS Plannen kunnen afhankelijk zijn van de apparatuur. Dus als u deze query's niet uitvoert, probeer dan de SomeData char(200)-kolomgrootte in de dbo.SalesOrder-tabelbeschrijving te vergroten of te verkleinen.

Het artikel is vertaald door het Codingsight-team met toestemming van de auteur.


  1. Geclusterde en niet-geclusterde index:7 toppunten uitgelegd

  2. Een Oracle Database 12c maken – Stap voor stap

  3. Welke bedrijfstakken profiteren het meest van toegang?

  4. Three table join met andere joins dan INNER JOIN