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

Problemer med tabel-værdi parameter ydeevne

Hvis TVP'er er "mærkbart langsommere" end de andre muligheder, er det højst sandsynligt, at du ikke implementerer dem korrekt.

  1. Du bør ikke bruge en datatabel, medmindre din applikation har brug for det uden for at sende værdierne til TVP. Brug IEnumerable<SqlDataRecord> grænsefladen er hurtigere og bruger mindre hukommelse, da du ikke duplikerer samlingen i hukommelsen kun for at sende den til DB. Jeg har dette dokumenteret følgende steder:
  2. Du bør ikke bruge AddWithValue for SqlParameter, selvom dette sandsynligvis ikke er et ydeevneproblem. Men alligevel skulle det være:

    SqlParameter tvp = com.Parameters.Add("data", SqlDbType.Structured);
    tvp.Value = MethodThatReturnsIEnumerable<SqlDataRecord>(MyCollection);
    
  3. TVP'er er tabelvariabler og vedligeholder som sådan ikke statistik. Det betyder, at de kun rapporterer at have 1 række til Query Optimizer. Så i din proc, enten:
    • Brug omkompilering på sætningsniveau på alle forespørgsler, der bruger TVP til alt andet end en simpel SELECT:OPTION (RECOMPILE)
    • Opret en lokal midlertidig tabel (dvs. enkelt # ) og kopier indholdet af TVP'en ind i temp-tabellen
    • Du kan prøve at tilføje en klynget primærnøgle til den brugerdefinerede tabeltype
    • Hvis du bruger SQL Server 2014 eller nyere, kan du prøve at bruge In-Memory OLTP/hukommelsesoptimerede tabeller. Se venligst:Hurtigere temperaturtabel og tabelvariabel ved at bruge hukommelsesoptimering

Med hensyn til hvorfor du ser:

insert into @data ( ... fields ... ) values ( ... values ... )
-- for each row
insert into @data ( ... fields ... ) values ( ... values ... )

i stedet for:

insert into @data ( ... fields ... ) 
values ( ... values ... ),
       ( ... values ... ),

HVIS det faktisk er det, der sker, så:

  • Hvis indsættelserne udføres inden for en transaktion, er der ingen reel forskel i ydeevne
  • Den nyere værdilistesyntaks (dvs. VALUES (row1), (row2), (row3) ) er begrænset til noget i retning af 1000 rækker og er derfor ikke en levedygtig mulighed for TVP'er, der ikke har den grænse. DOG er dette ikke sandsynligt årsagen til, at individuelle inserts bliver brugt, da der ikke er nogen grænse, når du laver INSERT INTO @data (fields) SELECT tab.[col] FROM (VALUES (), (), ...) tab([col]) , som jeg dokumenterede her:Maksimalt antal rækker for tabelværdikonstruktøren . I stedet...
  • Årsagen er højst sandsynligt, at individuelle indsættelser giver mulighed for at streame værdierne fra appkoden til SQL Server:
    1. ved at bruge en iterator (dvs. den IEnumerable<SqlDataRecord> noteret i #1 ovenfor), sender appkoden hver række, efterhånden som den returneres fra metoden, og
    2. konstruerer VALUES (), (), ... liste, selvom du gør INSERT INTO ... SELECT FROM (VALUES ...) tilgang (som ikke er begrænset til 1000 rækker), som stadig vil kræve opbygning af hele VALUES liste, før du sender enhver af dataene til SQL Server. Hvis der er mange data, ville det tage længere tid at konstruere den superlange streng, og det ville optage meget mere hukommelse, mens du gør det.

Se også denne hvidbog fra SQL Server Customer Advisory Team:Maksimering af gennemløb med TVP



  1. WordPress links alle omdirigerer til dobbelt URL

  2. Hvordan forbedres ydeevnen for dato- og tidsfiltrering i SQL Server?

  3. Unix-socket-forbindelse til MySql med Java for at undgå JDBC's TCP/IP-overhead?

  4. Ved at udtrække fra en stor xml fejler forespørgslen med strengen for lang