sql >> Database teknologi >  >> RDS >> Database

Generer et sæt eller en sekvens uden sløjfer – del 2

I mit tidligere indlæg talte jeg om måder at generere en sekvens af sammenhængende tal fra 1 til 1.000. Nu vil jeg gerne tale om de næste skalaniveauer:generering af sæt med 50.000 og 1.000.000 numre.

Generering af et sæt på 50.000 numre

Da jeg startede denne serie, var jeg virkelig nysgerrig på, hvordan de forskellige tilgange ville skalere til større sæt tal. I den lave ende var jeg lidt forfærdet over at finde ud af, at min yndlingsmetode – ved hjælp af sys.all_objects – var ikke den mest effektive metode. Men hvordan ville disse forskellige teknikker skaleres til 50.000 rækker?

    Taltabellen

    Da vi allerede har oprettet en Numbers-tabel med 1.000.000 rækker, forbliver denne forespørgsel stort set identisk:

    VÆLG TOP (50000) n FRA dbo.Numre BESTIL EFTER n;

    Plan:

    spt_values

    Da der kun er ~2.500 rækker i spt_values , skal vi være lidt mere kreative, hvis vi vil bruge det som kilden til vores sætgenerator. En måde at simulere en større tabel på er at CROSS JOIN det mod sig selv. Hvis vi gjorde det rå, ville vi ende med ~2.500 rækker i kvadrat (over 6 millioner). Behøver vi kun 50.000 rækker, har vi brug for omkring 224 rækker i kvadrat. Så vi kan gøre dette:

    ;WITH x AS ( SELECT TOP (224) number FROM [master]..spt_values)SELECT TOP (50000) n =ROW_NUMBER() OVER (ORDER BY x.number) FROM x CROSS JOIN x AS yORDER BY n; 

    Bemærk, at dette svarer til, men mere kortfattet end, denne variation:

    SELECT TOP (50000) n =ROW_NUMBER() OVER (ORDER BY x.number) FRA (SELECT TOP (224) nummer FRA [master]..spt_values) AS xCROSS JOIN(SELECT TOP (224) nummer FRA [master] ]..spt_values) SOM yORDER BY n;

    I begge tilfælde ser planen således ud:

    sys.all_objects

    Ligesom spt_values , sys.all_objects opfylder ikke helt vores krav på 50.000 rækker i sig selv, så vi bliver nødt til at udføre en lignende CROSS JOIN .

    ;;WITH x AS ( SELECT TOP (224) [object_id] FROM sys.all_objects)SELECT TOP (50000) n =ROW_NUMBER() OVER (ORDER BY x.[object_id]) FROM x CROSS JOIN x SOM y ORDRE AF n;

    Plan:

    Stablede CTE'er

    Vi behøver kun at foretage en mindre justering af vores stablede CTE'er for at få præcis 50.000 rækker:

    ;WITH e1(n) AS( VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1) , -- 10e2(n) AS (VÆLG 1 FRA e1 CROSS JOIN e1 AS b), -- 10*10e3(n) AS (SELECT 1 FROM e2 CROSS JOIN e2 AS b), -- 100*100e4(n) AS (VÆLG 1 FRA e3 CROSS JOIN (VÆLG TOP 5 n FRA e1) AS b) -- 5*10000 SELECT n =ROW_NUMBER() OVER (ORDER BY n) FROM e4 ORDER BY n;

    Plan:

    Rekursive CTE'er

    En endnu mindre væsentlig ændring er påkrævet for at få 50.000 rækker ud af vores rekursive CTE:skift WHERE klausul til 50.000 og ændre MAXRECURSION mulighed til nul.

    ;MED n(n) AS( VÆLG 1 UNION ALLE VÆLG n+1 FRA n HVOR n <50000)VÆLG n FRA n ORDEN VED nOPTION (MAXRECURSION 0);

    Plan:

    I dette tilfælde er der et advarselsikon på sorten - som det viser sig, på mit system, den slags, der skal til for at spilde til tempdb. Du kan muligvis ikke se et spild på dit system, men dette bør være en advarsel om de ressourcer, der kræves til denne teknik.

    Ydeevne

    Som med det sidste sæt af tests, vil vi sammenligne hver teknik, inklusive Numbers-tabellen med både en kold og varm cache og både komprimeret og ukomprimeret:


    Køretid, i millisekunder, for at generere 50.000 sammenhængende tal

    For at få et bedre syn, lad os fjerne den rekursive CTE, som var en total hund i denne test, og som skævvrider resultaterne:


    Køretid, i millisekunder, for at generere 50.000 sammenhængende tal (ekskl. CTE)

    Ved 1.000 rækker var forskellen mellem komprimeret og ukomprimeret marginal, da forespørgslen kun behøvede at læse henholdsvis 8 og 9 sider. Ved 50.000 rækker udvides afstanden en smule:74 sider vs. 113. De samlede omkostninger ved at dekomprimere dataene ser dog ud til at opveje besparelserne i I/O. Så ved 50.000 rækker ser en ukomprimeret taltabel ud til at være den mest effektive metode til at udlede et sammenhængende sæt - selvom fordelen ganske vist er marginal.

Generering af et sæt på 1.000.000 numre

Selvom jeg ikke kan forestille mig ret mange tilfælde, hvor du har brug for et sammenhængende sæt tal, så stort, ville jeg inkludere det for fuldstændighedens skyld, og fordi jeg lavede nogle interessante observationer i denne skala.

    Taltabellen

    Ingen overraskelser her, vores forespørgsel er nu:

    VÆLG TOP 1000000 n FRA dbo.Numre BESTIL EFTER n;

    TOP er ikke strengt nødvendigt, men det er kun fordi vi ved, at vores taltabel og vores ønskede output har det samme antal rækker. Planen er stadig ret lig tidligere tests:

    spt_values

    For at få en CROSS JOIN som giver 1.000.000 rækker, skal vi tage 1.000 rækker i kvadrat:

    ;MED x AS (VÆLG TOP (1000) nummer FRA [master]..spt_values)SELECT n =ROW_NUMBER() OVER (ORDER BY x.number) FROM x CROSS JOIN x AS y ORDER BY n;

    Plan:

    sys.all_objects

    Igen har vi brug for krydsproduktet af 1.000 rækker:

    ;WITH x AS (SELECT TOP (1000) [object_id] FROM sys.all_objects)SELECT n =ROW_NUMBER() OVER (ORDER BY x.[object_id]) FROM x CROSS JOIN x AS y ORDER BY n; 

    Plan:

    Stablede CTE'er

    Til den stablede CTE har vi bare brug for en lidt anderledes kombination af CROSS JOIN s for at komme til 1.000.000 rækker:

    ;WITH e1(n) AS( VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1 UNION ALLE VÆLG 1) , -- 10e2(n) AS (VÆLG 1 FRA e1 CROSS JOIN e1 AS b), -- 10*10e3(n) AS (SELECT 1 FROM e1 CROSS JOIN e2 AS b), -- 10*100e4(n) AS (VÆLG 1 FRA e3 CROSS JOIN e3 AS b) -- 1000*1000 SELECT n =ROW_NUMBER() OVER (ORDER BY n) FROM e4 ORDER BY n;

    Plan:

    Ved denne rækkestørrelse kan du se, at den stablede CTE-løsning går parallelt. Så jeg kørte også en version med MAXDOP 1 for at få en lignende planform som før, og for at se om parallelisme virkelig hjælper:

    Rekursiv CTE

    Den rekursive CTE har igen kun en mindre ændring; kun WHERE klausul skal ændres:

    ;MED n(n) AS( VÆLG 1 UNION ALLE VÆLG n+1 FRA n HVOR n <1000000)VÆLG n FRA n ORDEN EFTER nOPTION (MAXRECURSION 0);

    Plan:

    Ydeevne

    Endnu en gang ser vi, at ydeevnen af ​​den rekursive CTE er afgrundsdyb:


    Kørselstid i millisekunder for at generere 1.000.000 sammenhængende tal

    Hvis du fjerner denne udligger fra grafen, får vi et bedre billede af ydeevne:


    Køretid, i millisekunder, for at generere 1.000.000 sammenhængende recursive tal (ekskl. CTE)

    Selvom vi igen ser den ukomprimerede Numbers-tabel (i det mindste med en varm cache) som vinderen, er forskellen selv på denne skala ikke så bemærkelsesværdig.

Fortsættes...

Nu hvor vi grundigt har undersøgt en håndfuld tilgange til at generere en sekvens af tal, går vi videre til datoer. I det sidste indlæg i denne serie vil vi gennemgå opbygningen af ​​et datointerval som et sæt, inklusive brugen af ​​en kalendertabel og et par brugssager, hvor dette kan være praktisk.

[ Del 1 | Del 2 | Del 3 ]

Bilag :Rækketællinger

Du forsøger muligvis ikke at generere et nøjagtigt antal rækker; du vil måske i stedet bare have en ligetil måde at generere en masse rækker på. Det følgende er en liste over kombinationer af katalogvisninger, der vil give dig forskellige rækkeantal, hvis du blot SELECT uden en WHERE klausul. Bemærk, at disse tal vil afhænge af, om du er ved en RTM eller en service pack (da nogle systemobjekter bliver tilføjet eller ændret), og også om du har en tom database.

Kilde Rækkeantal
SQL Server 2008 R2 SQL Server 2012 SQL Server 2014
master..spt_values

2.508

2.515 2.519
master..spt_values ​​CROSS JOIN master..spt_values

6.290.064

6.325.225 6.345.361
sys.all_objects

1.990

2.089 2.165
sys.all_columns

5.157

7.276 8.560
sys.all_objects CROSS JOIN sys.all_objects

3.960.100

4.363.921 4.687.225
sys.all_objects CROSS JOIN sys.all_columns

10.262.430

15.199.564 18.532.400
sys.all_columns CROSS JOIN sys.all_columns

26.594.649

52.940.176 73.273.600

Tabel 1:Rækketællinger for forskellige katalogvisningsforespørgsler


  1. 4 funktioner, der returnerer minutterne fra en tidsværdi i MariaDB

  2. Sammenføjning af tre borde ved hjælp af MySQL

  3. Forårsaget af:java.lang.NoSuchMethodError:org.postgresql.core.BaseConnection.getEncoding()Lorg/postgresql/core/Encoding;

  4. Sådan finder du låste rækker i Oracle