sql >> Databasteknik >  >> RDS >> Sqlserver

Interner i de sju SQL-serversorterna – Del 2

De sju SQL Server-sorteringsimplementeringsklasserna är:

  1. CQScanSortNew
  2. CQScanTopSortNew
  3. CQScanIndexSortNew
  4. CQScanPartitionSortNew (endast SQL Server 2014)
  5. CQScanInMemSortNew
  6. In-Memory OLTP (Hekaton) inbyggt kompilerad procedur Top N Sort (endast SQL Server 2014)
  7. In-Memory OLTP (Hekaton) inbyggt kompilerad procedur General Sort (endast SQL Server 2014)

De fyra första typerna behandlades i del ett av denna artikel.

5. CQScanInMemSortNew

Den här sortens klass har ett antal intressanta funktioner, några av dem unika:

  • Som namnet antyder sorteras den alltid helt i minnet; det kommer aldrig att spilla till tempdb
  • Sorteringen utförs alltid med quicksort qsort_s i standard C runtime-biblioteket MSVCR100
  • Den kan utföra alla tre logiska sorteringstyperna:Allmänt, Top N och Distinkt sortering
  • Den kan användas för klustrade kolumnlager per partition mjuka sorteringar (se avsnitt 4 i del 1)
  • Minnet som den använder kan cachelagras med planen istället för att reserveras precis innan exekvering
  • Det kan identifieras som en sortering i minnet i exekveringsplaner
  • Högst 500 värden kan sorteras
  • Det används aldrig för indexbyggande sorteringar (se avsnitt 3 i del 1)

CQScanInMemSortNew är en sorts klass du inte kommer att stöta på ofta. Eftersom det alltid sorterar i minnet med hjälp av en vanlig bibliotekssnacksorteringsalgoritm, skulle det inte vara ett bra val för allmänna databassorteringsuppgifter. Faktum är att denna sorteringsklass endast används när alla dess indata är körtidskonstanter (inklusive @variable-referenser). Ur ett genomförandeplansperspektiv betyder det att indata till sorteringsoperatorn måste vara en Konstant skanning operator, som exemplen nedan visar:

-- Regular Sort on system scalar functions
SELECT X.i 
FROM 
(
    SELECT @@TIMETICKS UNION ALL
    SELECT @@TOTAL_ERRORS UNION ALL
    SELECT @@TOTAL_READ UNION ALL
    SELECT @@TOTAL_WRITE
) AS X (i)
ORDER BY X.i;
 
-- Distinct Sort on constant literals
WITH X (i) AS
(
    SELECT 3 UNION ALL
    SELECT 1 UNION ALL
    SELECT 1 UNION ALL
    SELECT 2
)
SELECT DISTINCT X.i
FROM X
ORDER BY X.i;
 
-- Top N Sort on variables, constants, and functions
DECLARE
    @x integer = 1,
    @y integer = 2;
 
SELECT TOP (1) 
    X.i
FROM 
(
    VALUES
        (@x), (@y), (123), 
        (@@CONNECTIONS)
) AS X (i)
ORDER BY X.i;

Utförandeplanerna är:

En typisk samtalsstack under sortering visas nedan. Lägg märke till anropet till qsort_s i MSVCR100-biblioteket:

Alla tre exekveringsplanerna som visas ovan är sorterade i minnet med CQScanInMemSortNew med ingångar som är tillräckligt små för att sorteringsminnet ska cachelagras. Denna information är inte exponerad som standard i exekveringsplaner, men den kan avslöjas med odokumenterad spårningsflagga 8666. När den flaggan är aktiv visas ytterligare egenskaper för sorteringsoperatorn:

Cachebufferten är begränsad till 62 rader i det här exemplet som visas nedan:

-- Cache buffer limited to 62 rows
SELECT X.i
FROM
(
    VALUES 
    (001),(002),(003),(004),(005),(006),(007),(008),(009),(010),
    (011),(012),(013),(014),(015),(016),(017),(018),(019),(020),
    (021),(022),(023),(024),(025),(026),(027),(028),(029),(030),
    (031),(032),(033),(034),(035),(036),(037),(038),(039),(040),
    (041),(042),(043),(044),(045),(046),(047),(048),(049),(050),
    (051),(052),(053),(054),(055),(056),(057),(058),(059),(060),
    (061),(062)--, (063)
) AS X (i)
ORDER BY X.i;

Avkommentera det sista objektet i det skriptet för att se egenskapen Sortera cachebuffert ändras från 1 till 0:

När bufferten inte är cachad måste sorteringen i minnet allokera minne när den initieras och efter behov när den läser rader från dess indata. När en cachad buffert kan användas undviks detta minnesallokeringsarbete.

Följande skript kan användas för att visa att det maximala antalet objekt för en CQScanInMemSortNew in-memory quicksort är 500:

SELECT X.i
FROM
(
    VALUES 
    (001),(002),(003),(004),(005),(006),(007),(008),(009),(010),
    (011),(012),(013),(014),(015),(016),(017),(018),(019),(020),
    (021),(022),(023),(024),(025),(026),(027),(028),(029),(030),
    (031),(032),(033),(034),(035),(036),(037),(038),(039),(040),
    (041),(042),(043),(044),(045),(046),(047),(048),(049),(050),
    (051),(052),(053),(054),(055),(056),(057),(058),(059),(060),
    (061),(062),(063),(064),(065),(066),(067),(068),(069),(070),
    (071),(072),(073),(074),(075),(076),(077),(078),(079),(080),
    (081),(082),(083),(084),(085),(086),(087),(088),(089),(090),
    (091),(092),(093),(094),(095),(096),(097),(098),(099),(100),
    (101),(102),(103),(104),(105),(106),(107),(108),(109),(110),
    (111),(112),(113),(114),(115),(116),(117),(118),(119),(120),
    (121),(122),(123),(124),(125),(126),(127),(128),(129),(130),
    (131),(132),(133),(134),(135),(136),(137),(138),(139),(140),
    (141),(142),(143),(144),(145),(146),(147),(148),(149),(150),
    (151),(152),(153),(154),(155),(156),(157),(158),(159),(160),
    (161),(162),(163),(164),(165),(166),(167),(168),(169),(170),
    (171),(172),(173),(174),(175),(176),(177),(178),(179),(180),
    (181),(182),(183),(184),(185),(186),(187),(188),(189),(190),
    (191),(192),(193),(194),(195),(196),(197),(198),(199),(200),
    (201),(202),(203),(204),(205),(206),(207),(208),(209),(210),
    (211),(212),(213),(214),(215),(216),(217),(218),(219),(220),
    (221),(222),(223),(224),(225),(226),(227),(228),(229),(230),
    (231),(232),(233),(234),(235),(236),(237),(238),(239),(240),
    (241),(242),(243),(244),(245),(246),(247),(248),(249),(250),
    (251),(252),(253),(254),(255),(256),(257),(258),(259),(260),
    (261),(262),(263),(264),(265),(266),(267),(268),(269),(270),
    (271),(272),(273),(274),(275),(276),(277),(278),(279),(280),
    (281),(282),(283),(284),(285),(286),(287),(288),(289),(290),
    (291),(292),(293),(294),(295),(296),(297),(298),(299),(300),
    (301),(302),(303),(304),(305),(306),(307),(308),(309),(310),
    (311),(312),(313),(314),(315),(316),(317),(318),(319),(320),
    (321),(322),(323),(324),(325),(326),(327),(328),(329),(330),
    (331),(332),(333),(334),(335),(336),(337),(338),(339),(340),
    (341),(342),(343),(344),(345),(346),(347),(348),(349),(350),
    (351),(352),(353),(354),(355),(356),(357),(358),(359),(360),
    (361),(362),(363),(364),(365),(366),(367),(368),(369),(370),
    (371),(372),(373),(374),(375),(376),(377),(378),(379),(380),
    (381),(382),(383),(384),(385),(386),(387),(388),(389),(390),
    (391),(392),(393),(394),(395),(396),(397),(398),(399),(400),
    (401),(402),(403),(404),(405),(406),(407),(408),(409),(410),
    (411),(412),(413),(414),(415),(416),(417),(418),(419),(420),
    (421),(422),(423),(424),(425),(426),(427),(428),(429),(430),
    (431),(432),(433),(434),(435),(436),(437),(438),(439),(440),
    (441),(442),(443),(444),(445),(446),(447),(448),(449),(450),
    (451),(452),(453),(454),(455),(456),(457),(458),(459),(460),
    (461),(462),(463),(464),(465),(466),(467),(468),(469),(470),
    (471),(472),(473),(474),(475),(476),(477),(478),(479),(480),
    (481),(482),(483),(484),(485),(486),(487),(488),(489),(490),
    (491),(492),(493),(494),(495),(496),(497),(498),(499),(500)
--,    (501)
) AS X (i)
ORDER BY X.i;

Återigen, avkommentera det sista objektet för att se InMemory Sortera egenskapsändring från 1 till 0. När detta händer, CQScanInMemSortNew ersätts av antingen CQScanSortNew (se avsnitt 1) ​​eller CQScanTopSortNew (sektion 2). En icke-CQScanInMemSortNew sortering kan fortfarande utföras i minnet, naturligtvis, den använder bara en annan algoritm och tillåts spridas till tempdb vid behov.

6. In-Memory OLTP inbyggt kompilerad lagrad procedur Top N Sort

Den nuvarande implementeringen av In-Memory OLTP (tidigare kodnamnet Hekaton) inbyggt kompilerade lagrade procedurer använder en prioritetskö följt av qsort_s för Top N Sorts, när följande villkor är uppfyllda:

  • Frågan innehåller TOP (N) med en ORDER BY-sats
  • Värdet på N är en konstant literal (inte en variabel)
  • N har ett maximalt värde på 8192; fastän
  • Närvaron av kopplingar eller aggregationer kan minska 8192-värdet som dokumenterats här

Följande kod skapar en Hekaton-tabell som innehåller 4000 rader:

CREATE DATABASE InMemoryOLTP;
GO
-- Add memory optimized filegroup
ALTER DATABASE InMemoryOLTP
ADD FILEGROUP InMemoryOLTPFileGroup 
CONTAINS MEMORY_OPTIMIZED_DATA;
GO
-- Add file (adjust path if necessary)
ALTER DATABASE InMemoryOLTP
ADD FILE
(
	NAME = N'IMOLTP', 
	FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL12.SQL2014\MSSQL\DATA\IMOLTP.hkf'
)
TO FILEGROUP InMemoryOLTPFileGroup;
GO
USE InMemoryOLTP;
GO
CREATE TABLE dbo.Test
(
    col1 integer NOT NULL,
    col2 integer NOT NULL,
    col3 integer NOT NULL,
 
    CONSTRAINT PK_dbo_Test
    PRIMARY KEY NONCLUSTERED HASH (col1)
    WITH (BUCKET_COUNT = 8192)
)
WITH
(
    MEMORY_OPTIMIZED = ON,
    DURABILITY = SCHEMA_ONLY
);
GO
-- Add numbers from 1-4000 using
-- Itzik Ben-Gan's number generator
WITH
  L0   AS (SELECT 1 AS c UNION ALL SELECT 1),
  L1   AS (SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B),
  L2   AS (SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B),
  L3   AS (SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B),
  L4   AS (SELECT 1 AS c FROM L3 AS A CROSS JOIN L3 AS B),
  L5   AS (SELECT 1 AS c FROM L4 AS A CROSS JOIN L4 AS B),
  Nums AS (SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS n FROM L5)
INSERT dbo.Test
    (col1, col2, col3)
SELECT 
    N.n,
    ABS(CHECKSUM(NEWID())),
    ABS(CHECKSUM(NEWID()))
FROM Nums AS N
WHERE N.n BETWEEN 1 AND 4000;

Nästa skript skapar en lämplig Top N Sortering i en inbyggt kompilerad lagrad procedur:

-- Natively-compiled Top N Sort stored procedure
CREATE PROCEDURE dbo.TestP
WITH EXECUTE AS OWNER, SCHEMABINDING, NATIVE_COMPILATION
AS
BEGIN ATOMIC 
WITH 
(
    TRANSACTION ISOLATION LEVEL = SNAPSHOT, 
    LANGUAGE = N'us_english'
)
    SELECT TOP (2) T.col2 
    FROM dbo.Test AS T
    ORDER BY T.col2
END;
GO
EXECUTE dbo.TestP;

Den beräknade genomförandeplanen är:

En anropsstack som fångas under körning visar infogningen till prioritetskön som pågår:

När prioriteringsköbygget är klart visar nästa samtalsstack en sista genomgång genom standardbibliotekets snabbsort:

xtp_p_* biblioteket som visas i dessa anropsstackar är den inbyggda kompilerade dll-filen för den lagrade proceduren, med källkoden sparad på den lokala SQL Server-instansen. Källkoden genereras automatiskt från den lagrade procedurens definition. Till exempel innehåller C-filen för denna ursprungliga lagrade procedur följande fragment:

Detta är så nära vi kan komma åt att ha tillgång till SQL Server-källkoden.

7. In-Memory OLTP inbyggt kompilerad lagrad procedur Sortera

Inbyggt kompilerade procedurer stöder för närvarande inte Distinkt sortering, men icke-distinkt allmän sortering stöds, utan några begränsningar på uppsättningens storlek. För att demonstrera kommer vi först att lägga till 6 000 rader i testtabellen, vilket ger totalt 10 000 rader:

WITH
  L0   AS (SELECT 1 AS c UNION ALL SELECT 1),
  L1   AS (SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B),
  L2   AS (SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B),
  L3   AS (SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B),
  L4   AS (SELECT 1 AS c FROM L3 AS A CROSS JOIN L3 AS B),
  L5   AS (SELECT 1 AS c FROM L4 AS A CROSS JOIN L4 AS B),
  Nums AS (SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS n FROM L5)
INSERT dbo.Test
    (col1, col2, col3)
SELECT 
    N.n,
    ABS(CHECKSUM(NEWID())),
    ABS(CHECKSUM(NEWID()))
FROM Nums AS N
WHERE N.n BETWEEN 4001 AND 10000;

Nu kan vi släppa den tidigare testproceduren (nativet-kompilerade procedurer kan för närvarande inte ändras) och skapa en ny som utför en vanlig (inte top-n) sort av de 10 000 raderna:

DROP PROCEDURE dbo.TestP;
GO
CREATE PROCEDURE dbo.TestP
WITH EXECUTE AS OWNER, SCHEMABINDING, NATIVE_COMPILATION
AS
BEGIN ATOMIC 
WITH 
(
    TRANSACTION ISOLATION LEVEL = SNAPSHOT, 
    LANGUAGE = N'us_english'
)
    SELECT T.col2 
    FROM dbo.Test AS T
    ORDER BY T.col2
END;
GO
EXECUTE dbo.TestP;

Den beräknade genomförandeplanen är:

Att spåra exekveringen av denna sort visar att den börjar med att generera flera små sorterade körningar med standardbibliotekets snabbsortering igen:

När den processen är klar slås de sorterade körningarna samman med ett prioritetsköschema:

Återigen visar C-källkoden för proceduren några av detaljerna:

Sammanfattning av del 2

  • CQScanInMemSortNew är alltid en snabbsort i minnet. Den är begränsad till 500 rader från en konstant skanning och kan cachelagra dess sorteringsminne för små ingångar. En sortering kan identifieras som en CQScanInMemSortNew sortera med exekveringsplansegenskaper exponerade av spårningsflagga 8666.
  • Hekaton inbyggd kompilerad Top N Sortering kräver ett konstant bokstavligt värde för N <=8192 och sorterar med hjälp av en prioritetskö följt av en standard snabbsortering
  • Hekatons inbyggda kompilerade General Sort kan sortera valfritt antal rader, med hjälp av standardbibliotekssnacksortering för att generera sorteringskörningar, och en prioriterad kösammanslagning för att kombinera körningar. Den stöder inte Distinct Sort.

  1. PHP &mySQL:År 2038 Bug:Vad är det? Hur löser man det?

  2. Vad är RDBMS (Databas and Relational Database Management System)

  3. Hämta den aktuella tidszonen för servern i SQL Server (T-SQL)

  4. Återställer åtkomst till SQL Server-instansen utan att starta om