Scroll
Jeg fik for nylig en lidt sjov opgave fra en af mine kollegaer.
Vi har opgraderet en kundes setup fra SQL 2008 til SQL 2017, alt fra SQL 2008 blev kopieret 1:1 til SQL 2017. Udfordringen var at på SQL 2017 performede det en smule langsommere end på SQL 2008.
 
Efter at have kigget i plancache hvor jeg fandt det Query, der var tale om, kiggede jeg i SQL Query executionplan.
 
Query så ca. sådan her ud:
DECLARE @p0 FLOAT = 1.2840000000000000e+001,
@p1 FLOAT = 5.6609859999999998e+001,
@p2 VARCHAR(2) = 'da'

SELECT top 200
latitude,
longitute,
language_desc
FROM dbo.Geo
WHERE (latitude = @p0) AND (longitute = @p1) AND (language_desc = @p2)
Og execution plan sådan her:
Der er ingen warnings i planen, men bemærk at der er en constant scan så en compute scalar, for derefter at joine på tabellen. Da vi kun har fat i en tabel, var det en lidt mærkelig plan og det fortæller at der sker noget, som ikke er optimalt for vores performance. Så lad os lige dykke ned i XML queryplanen:

Og her ses det hvorfor vi har en constant scan, det er pga. implicit conversions i vores where clause.

Da databaserne og SQL forespørgslen er 100% ens i begge versioner, betyder det også at der er implicit_conversion i den gamle 2008 version.. men hvorfor performer det bedre?

Min mistanke gik på om den interne funktion <Intrinsic FunctionName=”GetRangeThroughConvert”> var ændret imellem de 2 versioner og derved performer lidt langsommere i lige netop dette eksempel.

Så for at finde ud af det, laver jeg en lille test.

Jeg opretter 2 databaser:

Begge med den eksakt samme tabel og det samme index og samme antal rækker.

Inden jeg helt kaster mig ud i testen, så er det ret let at fikse den implicit:_conversion da datatyperne i tabellen er af typen decimal, så skal variablen selvfølgelig også være samme datatype. Da det kaldende program var egenudviklet hos kunden var det let for dem at rette datatypen til. Dette betød at performance gik fra 6-8000 requests i timen til 130000 requests i timen. Jeg siger det ofte når jeg underviser: husk nu at have styr på datatyperne, det betyder faktisk en del i performance.

Anyways tilbage til testen. Herunder kommer resultatet af testen.Til min overraskelse så ligger forskellen i performance i den tid SQL 2017 bruger på at compile Query, det performer langsommere end på 2008. Det ser ud til at det skifter mellem version 2012 og 2014.

Jeg benytter mig af nogle traceflags for at se det plantree SQL Serverens optimizer laver til Query.

QUERY:

SET STATISTICS IO, TIME ON;
GO
DBCC TRACEON(3604)

DECLARE @p0 FLOAT = 1.2840000000000000e+001,
@p1 FLOAT = 5.6609859999999998e+001,
@p2 VARCHAR(2) = 'da'

SELECT top 200
latitude,
longitute,
language_desc
FROM dbo.Geo
WHERE (latitude = @p0) AND (longitute = @p1) AND (language_desc = @p2)
OPTION(RECOMPILE,QUERYTRACEON 8605, QUERYTRACEON 8675)
Execution plan:
Executionplan XML:
<ScalarOperator ScalarString="GetRangeThroughConvert([@p0],[@p0],(62))">
                              <Intrinsic FunctionName="GetRangeThroughConvert">
                                <ScalarOperator>
                                  <Identifier>
                                    <ColumnReference Column="@p0" />
                                  </Identifier>
                                </ScalarOperator>
                                <ScalarOperator>
                                  <Identifier>
                                    <ColumnReference Column="@p0" />
                                  </Identifier>
                                </ScalarOperator>
                                <ScalarOperator>
                                  <Const ConstValue="(62)" />
                                </ScalarOperator>
                              </Intrinsic>
                            </ScalarOperator>
SQL2017:
End of simplification, time: 0 net: 0 total: 0 net: 0
End of post optimization rewrite, time: 0 net: 0 total: 0 net: 0.001
End of query plan compilation, time: 0.003 net: 0.003 total: 0 net: 0.005
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 5 ms

SQL2008:
End of simplification, time: 0 net: 0 total: 0 net: 0
End of post optimization rewrite, time: 0.001 net: 0.001 total: 0 net: 0.002
End of query plan compilation, time: 0 net: 0 total: 0 net: 0.002
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 3 ms.

Spørgsmålet, som jeg endnu ikke har testet af, er hvis planen er cahed og bliver genbrugt, er der så forskel i performance?

Har du SQL Query, der performer knapt så optimalt, som du godt kunne ønske dig, eller vil du bare gerne have kigget din SQL Server igennem med henblik på performance optimering, så tage endelig fat i mig eller en af mine dygtige kollegaer i Unit IT; ring gerne på tlf.: 88 33 33 33

Ring til Danmarks Mest Anbefalede Virksomhed 2020