Her parti bir derlemeye neden olur


10

T-SQL ifadelerini toplu olarak gönderen bir üçüncü taraf uygulamamız var.

Veritabanı bir SQL Server 2016 Enterprise SP1 CU7, 16 çekirdek ve 256 GB bellek üzerinde barındırılmaktadır. Geçici için En İyi Duruma Getir etkin.

Bu, yürütülmekte olan sorguların bir kukla örneğidir:

exec sp_executesql N'
IF @@TRANCOUNT = 0 SET TRANSACTION ISOLATION LEVEL SNAPSHOT

select field1, field2 from table1 where field1=@1
option(keep plan, keepfixed, loop join)

select field3, field4 from table2 where field3=@1
option(keep plan, keepfixed, loop join)', N'@1 nvarchar(6)',@1=N'test'

Veritabanını izlediğimde, toplu iş / saniye ve derleme / saniye konularına baktığımda, her zaman aynı olduklarını fark ettim. Ağır yük altında, bu 1000 parti / sn ve 1000 derleme / sn olabilir. Ortalama yük altında, 150 parti / saniye vardır.

Son derlenen planlar için sorgu önbelleğini analiz ediyorum:

SELECT TOP (1000) qs.creation_time
    , DatabaseName = DB_NAME(st.dbid)
    , qs.execution_count
    , st.text
    , qs.plan_handle
    , qs.sql_handle
    , qs.query_hash 
FROM sys.dm_exec_query_stats qs
    CROSS APPLY sys.dm_exec_sql_text(qs.plan_handle) AS st
ORDER BY creation_time DESC;

Sorgunun üzerinde çalıştığımda sadece 10-20 yeni sorgu planları / sn görüyorum.

Her sp_executesqlçağrı bir derlemeyi tetikler ama sorgu planı önbelleğe alınmaz.

Yığın / sn'nin derleme / sn'ye eşit olmasının nedeni ne olabilir?

Yanıtlar:


12

Her sp_executesqlçağrı bir derlemeyi tetikler ama sorgu planı önbelleğe alınmaz.

SQL Server , yalnızca bir sp_executesqlçağrı içeren gruplar için bir sorgu planını önbelleğe almaz . Önbelleğe alınmış bir plan olmadan, her seferinde bir derleme gerçekleşir. Bu tasarım ve beklenen.

SQL Server, derleme maliyeti düşük olan önbellekleme yığınlarını önler. Önbelleğe alınan ve önbelleğe alınmayanların ayrıntıları yıllar boyunca birçok kez değişti. İzleme bayrağı 2861'e cevabımı ve ayrıntılar için 'sıfır maliyet' planının gerçekte ne anlama geldiğini görün .

Kısacası, yeniden kullanım olasılığı (belirli parametre değerleri dahil) küçüktür ve sp_executesqlçağrıyı içeren geçici metni derleme maliyeti çok düşüktür. Ürettiği iç parametreli parti sp_executesqlelbette önbelleğe alınır ve yeniden kullanılır - bu onun değeridir. Genişletilmiş saklı yordamın sp_executesqlkendisi de önbelleğe alınır.

Önbelleğe alınması ve yeniden kullanılması için, sp_executesqlifadenin önbelleğe alınmaya değer olduğu düşünülen daha büyük bir grubun parçası olması gerekir. Örneğin:

-- Show compilation counter
SELECT
    DOPC.[object_name],
    DOPC.cntr_value
FROM sys.dm_os_performance_counters AS DOPC
WHERE
    DOPC.counter_name = N'SQL Compilations/sec'
GO
-- This is only here to make the batch worth caching
DECLARE @TC integer =
(
    SELECT TOP (1) @@TRANCOUNT 
    FROM master.dbo.spt_values AS SV
);

-- Example call we are testing
-- (use anything for the inner query, this example uses the Stack Overflow database
EXECUTE sys.sp_executesql 
    N'SELECT LT.Type FROM dbo.LinkTypes AS LT WHERE LT.Id = @id;', 
    N'@id int', 
    @id = 1;
GO
-- Show compilation counter again
SELECT
    DOPC.[object_name],
    DOPC.cntr_value
FROM sys.dm_os_performance_counters AS DOPC
WHERE
    DOPC.counter_name = N'SQL Compilations/sec'

Bu kodu birkaç kez çalıştırın. Yine de ilk defa birçok derleme beklendiği gibi rapor edildi. İkinci kez, optimize for ad hoc workloadsetkinleştirilmedikçe hiçbir derleme bildirilmez (bu nedenle yalnızca Derlenmiş Plan Saplaması önbelleğe alınır). Üçüncü kez, herhangi bir derleme rapor edilmez, çünkü herhangi bir saplama tamamen önbelleğe alınmış geçici bir plana yükseltilir.

İfadenin kaç kez çalıştırıldığına bakılmaksızın DECLARE @TC, sys.sp_executesqlifadenin hiçbir zaman önbelleğe alınmadığını görmek için ifadeyi kaldırın .

İlişkili plan önbellek girdilerini şununla görüntüleyin:

-- Show cached plans
SELECT
    DECP.refcounts,
    DECP.usecounts,
    DECP.size_in_bytes,
    DECP.cacheobjtype,
    DECP.objtype,
    DECP.plan_handle,
    DECP.parent_plan_handle,
    DEST.[text]
FROM sys.dm_exec_cached_plans AS DECP
CROSS APPLY sys.dm_exec_sql_text(DECP.plan_handle) AS DEST
WHERE 
    DEST.[text] LIKE N'%sp_executesql%'
    AND DEST.[text] NOT LIKE N'%dm_exec_cached_plans%';

İlgili Sorular ve Cevaplar: Tetikleyiciler her seferinde derleniyor mu?


11

Sizin için performans izleyicisi ve Aktivite Monitörü gördükleri tahmin edebilir SQL Compilations/secve Batch Requests/secbir test olarak ayrı bir sorgu penceresinde bazı toplu çalışırken aşağıda ayrıntılı olarak,.

Sorgu Penceresi 1:

DECLARE @t1 datetime;
DECLARE @t2 datetime;
DECLARE @CompVal1 int;
DECLARE @CompVal2 int;
DECLARE @ReCompVal1 int;
DECLARE @ReCompVal2 int;
DECLARE @BatchVal1 int;
DECLARE @BatchVal2 int;
DECLARE @ElapsedMS decimal(10,2);

SELECT @t1 = GETDATE()
    , @CompVal1 = (
        SELECT spi.cntr_value
        FROM sys.sysperfinfo spi
        WHERE spi.counter_name = 'SQL Compilations/sec                                                                                                            '
        )
    , @ReCompVal1 = (
        SELECT spi.cntr_value
        FROM sys.sysperfinfo spi
        WHERE spi.counter_name = 'SQL Re-Compilations/sec                                                                                                         '
        )
    , @BatchVal1 = (
        SELECT spi.cntr_value
        FROM sys.sysperfinfo spi
        WHERE spi.counter_name = 'Batch Requests/sec                                                                                                              '
        );

WAITFOR DELAY '00:00:10.000';

SELECT @t2 = GETDATE()
    , @CompVal2 = (
        SELECT spi.cntr_value
        FROM sys.sysperfinfo spi
        WHERE spi.counter_name = 'SQL Compilations/sec                                                                                                            '
        )
    , @ReCompVal2 = (
        SELECT spi.cntr_value
        FROM sys.sysperfinfo spi
        WHERE spi.counter_name = 'SQL Re-Compilations/sec                                                                                                         '
        )
    , @BatchVal2 = (
        SELECT spi.cntr_value
        FROM sys.sysperfinfo spi
        WHERE spi.counter_name = 'Batch Requests/sec                                                                                                              '
        );

SET @ElapsedMS = DATEDIFF(MILLISECOND, @t1, @t2);
SELECT  ElapsedTimeMS = @ElapsedMS
    , [SQL Compilations/sec] = (@CompVal2 - @CompVal1) / @ElapsedMS * 1000 
    , [SQL Recompilations/sec] = (@ReCompVal2 - @ReCompVal1) / @ElapsedMS * 1000
    , [Batch Requests/sec] = (@BatchVal2 - @BatchVal1) / @ElapsedMS * 1000;

Sorgu Penceresi 2'de, yukarıdaki kod çalışırken aşağıdakileri çalıştırın. Kod sadece 100 T-SQL toplu işlemi yürütür:

EXEC sys.sp_executesql N'SELECT TOP(1) o.name FROM sys.objects o;';
GO 100

Sorgu Penceresi 1'e geri dönerseniz aşağıdaki gibi bir şey görürsünüz:

╔═══════════════╦══════════════════════╦══════════ ══════════════╦════════════════════╗
║ ElapsedTimeMS ║ SQL Derlemeleri / sn ║ SQL Yeniden Derlemeleri / sn ║ Toplu İstekler / sn ║
╠═══════════════╬══════════════════════╬══════════ ══════════════╬════════════════════╣
10020,00 ₺ 10,07984031000 ║ 0,00000000000 ║ 10,07984031000 ║
╚═══════════════╩══════════════════════╩══════════ ══════════════╩════════════════════╝

Bu sorguya bakarsak:

SELECT dest.text
    , deqs.execution_count
FROM sys.dm_exec_query_stats deqs
    CROSS APPLY sys.dm_exec_sql_text(deqs.plan_handle) dest
WHERE dest.text LIKE 'SELECT TOP(1)%'

Test sorgusunun 100 yürütme olduğunu doğrulayabiliriz.

Yukarıdaki sonuçlarda , ifadenin hersp_executesql çalıştırılışında derlemeler aldığımızı görebilirsiniz . Bunun planı kesinlikle önbelleğe alınıyor, ancak bunun için bir derleme görüyoruz; ne oluyor?

Microsoft Dokümanlar Bu konuda söyleyecek sp_executesql:

sp_executesql, gruplar, adların kapsamı ve veritabanı bağlamında EXECUTE ile aynı davranışa sahiptir. Sp_executesql @stmt parametresindeki Transact-SQL deyimi veya toplu iş, sp_executesql deyimi yürütülene kadar derlenmez. @Stmt içeriği daha sonra derlenir ve sp_executesql adlı toplu işin yürütme planından ayrı bir yürütme planı olarak yürütülür.

Bu nedenle, komut metni için plan zaten plan önbelleğinde olsa bile , sp_executesql kendisi her çalıştığında derlenmektedir. @PaulWhite yanıtında sp_executesql'e yapılan çağrıların çoğunun önbelleğe alınmadığını gösterir .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.