ทุกชุดทำให้เกิดการคอมไพล์


10

เรามีแอปพลิเคชันบุคคลที่สามที่ส่งคำสั่ง T-SQL เป็นชุด

ฐานข้อมูลโฮสต์อยู่ใน SQL Server 2016 Enterprise SP1 CU7, 16 คอร์และหน่วยความจำ 256GB เปิดใช้งานการปรับให้เหมาะสมที่สุดสำหรับ Ad-Hoc

นี่เป็นตัวอย่างของการสอบถามที่กำลังดำเนินการ:

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'

เมื่อฉันตรวจสอบฐานข้อมูลและฉันดูแบตช์ / วินาทีและคอมไพล์ / วินาทีฉันสังเกตว่ามันเหมือนกันเสมอ ภายใต้ภาระหนักนี้สามารถเป็น 1000 batches / วินาทีและ 1000 compiles / วินาที ภายใต้ภาระเฉลี่ยมี 150 กระบวนการ / วินาที

ฉันวิเคราะห์แคชแบบสอบถามสำหรับแผนที่ที่รวบรวมเมื่อเร็ว ๆ นี้:

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;

เมื่อฉันเรียกใช้แบบสอบถามข้างต้นฉันเห็นแผนแบบสอบถาม 10-20 แผน / วินาทีเท่านั้น

มันก็เหมือนกับการsp_executesqlโทรทุกครั้งจะก่อให้เกิดการคอมไพล์ แต่แบบสอบถามไม่ได้ถูกแคช

อะไรเป็นสาเหตุของการแบทช์ / วินาทีที่เท่ากับคอมไพล์ / วินาที

คำตอบ:


12

มันก็เหมือนกับการsp_executesqlโทรทุกครั้งจะก่อให้เกิดการคอมไพล์ แต่แผนแบบสอบถามไม่ได้ถูกแคช

SQL Server ไม่แคชแผนแบบสอบถามสำหรับแบตช์ที่มีเพียงการsp_executesqlโทร หากไม่มีแผนแคชการรวบรวมจะเกิดขึ้นทุกครั้ง นี่คือโดยการออกแบบและคาดว่า

SQL Server หลีกเลี่ยงการแคชแบตช์ด้วยต้นทุนต่ำในการคอมไพล์ รายละเอียดของสิ่งที่เป็นและไม่แคชมีการเปลี่ยนแปลงหลายครั้งในช่วงหลายปีที่ผ่านมา ดูคำตอบของฉันในการติดตามการตั้งค่าสถานะ 2861 และแผน 'ศูนย์ต้นทุน' มีความหมายอย่างไรสำหรับรายละเอียด

กล่าวโดยสรุปความน่าจะเป็นที่จะนำกลับมาใช้ใหม่ (รวมถึงค่าพารามิเตอร์เฉพาะ) มีขนาดเล็กและค่าใช้จ่ายในการรวบรวมข้อความ ad hoc ที่มีการsp_executesqlโทรมีขนาดเล็กมาก ชุดพารามิเตอร์ภายในที่สร้างขึ้นโดยsp_executesqlแน่นอนเก็บไว้และนำกลับมาใช้ใหม่ - นี่คือค่าของมัน ขั้นตอนการจัดเก็บขยายsp_executesqlตัวเองก็จะถูกแคช

หากต้องการแคชและนำกลับมาใช้ใหม่sp_executesqlคำสั่งจะต้องเป็นส่วนหนึ่งของชุดที่มีขนาดใหญ่กว่าซึ่งถือว่าคุ้มค่าที่จะทำการแคช ตัวอย่างเช่น:

-- 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'

เรียกใช้รหัสนั้นหลายครั้ง ในครั้งแรกแม้ว่าจะมีการรวบรวมรายงานจำนวนมากตามที่คาดไว้ ในครั้งที่สองจะไม่มีการรายงานการรวบรวมเว้นแต่optimize for ad hoc workloadsจะเปิดใช้งาน (ดังนั้นเฉพาะการรวบรวมแผนสตับเท่านั้นที่จะถูกแคช) ในครั้งที่สามจะไม่มีการรวบรวมการรายงานในกรณีใด ๆ เนื่องจาก stub ใด ๆ ได้รับการเลื่อนไปยังแผนเฉพาะกิจที่แคชไว้อย่างสมบูรณ์

ลบDECLARE @TCคำสั่งเพื่อดูว่าsys.sp_executesqlคำสั่งไม่เคยถูกแคชหากไม่มีคำสั่งไม่ว่าจะมีการดำเนินการกี่ครั้งก็ตาม

ดูรายการแคชแผนที่เกี่ยวข้องด้วย:

-- 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%';

คำถาม & คำตอบที่เกี่ยวข้อง: ทริกเกอร์รวบรวมในแต่ละครั้งหรือไม่


11

คุณสามารถประมาณสิ่งที่คุณเห็นในการตรวจสอบประสิทธิภาพและการตรวจสอบกิจกรรมสำหรับSQL Compilations/secและBatch Requests/secในขณะที่ใช้ชุดงานบางอย่างในหน้าต่างแบบสอบถามแยกเป็นการทดสอบตามรายละเอียดด้านล่าง

หน้าต่างค้นหา 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;

ใน Query Window 2 ให้เรียกใช้สิ่งต่อไปนี้ขณะที่เรียกใช้รหัสข้างต้น รหัสนี้จะประมวลผลชุดที่ 100 ของ T-SQL:

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

หากคุณเปลี่ยนกลับไปใช้ Query Window 1 คุณจะเห็นสิ่งนี้:

╔═══════════════╦══════════════════════╦══════════ ══════════════╦════════════════════╗
║ ElapsedTimeMS ║การคอมไพล์ด้วย SQL / วินาที║การคอมไพล์ของ SQL / วินาที Requ การร้องขอแบตช์ / วินาที║
╠═══════════════╬══════════════════════╬══════════ ══════════════╬════════════════════╣
║ 10020.00 ║ 10.07984031000 ║ 0.00000000000 ║ 10.07984031000 ║
╚═══════════════╩══════════════════════╩══════════ ══════════════╩════════════════════╝

ถ้าเราดูคำถามนี้:

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)%'

เราสามารถยืนยันได้ว่ามีการประมวลผล 100 ครั้งของแบบสอบถามทดสอบ

ในผลลัพธ์ข้างต้นคุณจะเห็นว่าเราได้รับการรวบรวมทุกครั้งที่มีการsp_executesqlเรียกใช้คำสั่ง แผนการสำหรับสิ่งนั้นถูกแคชไว้อย่างแน่นอน แต่เราก็เห็นการเรียบเรียง สิ่งที่ช่วยให้?

เอกสาร Microsoftพูดนี้เกี่ยวกับsp_executesql:

sp_executesql มีพฤติกรรมเช่นเดียวกับ EXECUTE เกี่ยวกับแบตช์ขอบเขตของชื่อและบริบทฐานข้อมูล คำสั่ง Transact-SQL หรือแบตช์ในพารามิเตอร์ sp_executesql @stmt จะไม่ถูกคอมไพล์จนกว่าจะรันคำสั่ง sp_executesql เนื้อหาของ @stmt จะถูกรวบรวมและดำเนินการตามแผนการดำเนินการแยกต่างหากจากแผนการดำเนินการของแบทช์ที่เรียกว่า sp_executesql

ดังนั้นsp_executesql ตัวเองจะถูกรวบรวมทุกครั้งที่มันทำงานแม้ว่าแผนสำหรับข้อความคำสั่งที่มีอยู่แล้วในแคชแผน @PaulWhite แสดงให้เห็นในคำตอบของเขาว่าส่วนใหญ่โทรไปยัง sp_executesql ไม่ได้เก็บไว้จริง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.