ในลูกค้ารายหนึ่งของเราเราพบปัญหาเกี่ยวกับประสิทธิภาพในการสมัครของเรา เป็นแอปพลิเคชั่นเว็บ. NET 3.5 ที่ใช้งานและอัพเดทข้อมูลในฐานข้อมูล SQL Server ปัจจุบันสภาพแวดล้อมการผลิตของเราประกอบด้วยเครื่อง Windows 2008 R2 เป็นส่วนหน้าและคลัสเตอร์ SQL Server 2008 R2 ที่ส่วนหลัง แอพของเราใช้ COM + และ MSDTC เพื่อเชื่อมต่อกับฐานข้อมูล
นี่คือสิ่งที่เกิดขึ้น: บางครั้งผู้ใช้ของเราบ่นว่าความเชื่องช้าในแอปพลิเคชัน บางหน้าใช้เวลาโหลดมากกว่าที่คาดไว้ ในขณะที่พยายามคิดว่าเกิดอะไรขึ้นฉันพยายามหาพฤติกรรมแปลก ๆ ในด้านฐานข้อมูลที่อาจเป็นสาเหตุให้ประสิทธิภาพการทำงานลดลง ฉันสังเกตเห็นว่าบางครั้งมีคำสั่ง SQL บางคำที่ต้องใช้เวลามากในการรันสิ่งที่คาดหวัง ฉันจัดการเพื่อระบุบางส่วนของคำสั่งเหล่านี้ (ส่วนใหญ่เป็นการเรียกร้องให้บางส่วนของขั้นตอนการจัดเก็บใบสมัครของเรา) โดยใช้การติดตาม profiler (ด้วยแม่แบบ TSQL_Duration) เพื่อระบุการสืบค้นที่ใช้เวลานาน
ปัญหาคือเมื่อฉันเรียกใช้ขั้นตอนการจัดเก็บเหล่านี้โดยตรงในฐานข้อมูลใน SQL Management Studio บางครั้งพวกเขาใช้เวลานาน (ประมาณ 7/8 วินาที) บางครั้งก็รวดเร็ว (น้อยกว่า 1 วินาที) ฉันไม่รู้ว่าทำไมสิ่งนี้ถึงเกิดขึ้นและมันทำให้ฉันสับสนเพราะเครื่อง SQL (4 คอร์, 32 GB) ไม่ได้ถูกใช้โดยแอพพลิเคชั่นอื่นและแบบสอบถามเหล่านี้ไม่ควรใช้เวลานานในการรัน
ไม่ใช่การเป็น DBA หรือกูรูเซิร์ฟเวอร์ SQL ฉันพยายามค้นหาสิ่งที่อาจช่วยให้ฉันเข้าใจปัญหา นี่คือขั้นตอนที่ฉันพยายามทำและแยกแยะปัญหาและสิ่งที่ฉันค้นพบ:
- รหัส TSQL ทั้งหมดที่เรียกใช้โดยแอปพลิเคชันจะถูกเขียนในขั้นตอนการจัดเก็บ
- ฉันระบุข้อความค้นหาที่ใช้เวลานานใน SQL Server Profiler แต่เมื่อฉันเรียกใช้งานเหล่านี้ใน Management Studio พวกเขาอาจใช้เวลานานในการรัน (จาก 4 ถึง 10 วินาที) หรือทำงานอย่างรวดเร็ว (ต่ำกว่า 1 วินาที) ฉันกำลังเรียกใช้คำค้นหาเดียวกันที่แน่นอนด้วยข้อมูลเดียวกันที่ส่งผ่านในพารามิเตอร์ แบบสอบถามเหล่านี้ส่วนใหญ่จะถูกจัดเก็บด้วยวิธีการเลือกคำสั่งในพวกเขา
- ฉันลองดูสถิติการรอและรอเพื่อลองและคิดออกว่ามีกระบวนการรอทรัพยากรบางอย่างอยู่หรือไม่ ฉันเรียกใช้แบบสอบถามต่อไปนี้:
WITH Waits AS
(SELECT
wait_type,
wait_time_ms / 1000.0 AS WaitS,
(wait_time_ms - signal_wait_time_ms) / 1000.0 AS ResourceS,
signal_wait_time_ms / 1000.0 AS SignalS,
waiting_tasks_count AS WaitCount,
100.0 * wait_time_ms / SUM (wait_time_ms) OVER() AS Percentage,
ROW_NUMBER() OVER(ORDER BY wait_time_ms DESC) AS RowNum
FROM sys.dm_os_wait_stats
WHERE wait_type NOT IN (
'CLR_SEMAPHORE', 'LAZYWRITER_SLEEP', 'RESOURCE_QUEUE', 'SLEEP_TASK',
'SLEEP_SYSTEMTASK', 'SQLTRACE_BUFFER_FLUSH', 'WAITFOR', 'LOGMGR_QUEUE',
'CHECKPOINT_QUEUE', 'REQUEST_FOR_DEADLOCK_SEARCH', 'XE_TIMER_EVENT', 'BROKER_TO_FLUSH',
'BROKER_TASK_STOP', 'CLR_MANUAL_EVENT', 'CLR_AUTO_EVENT', 'DISPATCHER_QUEUE_SEMAPHORE',
'FT_IFTS_SCHEDULER_IDLE_WAIT', 'XE_DISPATCHER_WAIT', 'XE_DISPATCHER_JOIN', 'BROKER_EVENTHANDLER',
'TRACEWRITE', 'FT_IFTSHC_MUTEX', 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
'BROKER_RECEIVE_WAITFOR', 'ONDEMAND_TASK_QUEUE', 'DBMIRROR_EVENTS_QUEUE',
'DBMIRRORING_CMD', 'BROKER_TRANSMITTER', 'SQLTRACE_WAIT_ENTRIES',
'SLEEP_BPOOL_FLUSH', 'SQLTRACE_LOCK')
)
SELECT
W1.wait_type AS WaitType,
CAST (W1.WaitS AS DECIMAL(14, 2)) AS Wait_S,
CAST (W1.ResourceS AS DECIMAL(14, 2)) AS Resource_S,
CAST (W1.SignalS AS DECIMAL(14, 2)) AS Signal_S,
W1.WaitCount AS WaitCount,
CAST (W1.Percentage AS DECIMAL(4, 2)) AS Percentage,
CAST ((W1.WaitS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgWait_S,
CAST ((W1.ResourceS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgRes_S,
CAST ((W1.SignalS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgSig_S
FROM Waits AS W1
INNER JOIN Waits AS W2 ON W2.RowNum <= W1.RowNum
GROUP BY W1.RowNum, W1.wait_type, W1.WaitS, W1.ResourceS, W1.SignalS, W1.WaitCount, W1.Percentage
HAVING SUM (W2.Percentage) - W1.Percentage < 95; -- percentage threshold
GO
นี่คือสิ่งที่ฉันค้นพบ:
- หลังจากฉันรีเซ็ตสถิติโดยใช้ DBCC SQLPERF (ประมาณ 1 หรือ 2 ชั่วโมงหลังจากนั้น) ประเภทการรอที่ฉันมีมากที่สุดคือ SOS_SCHEDULER_YIELD และ WRITELOG
- เมื่อเวลาผ่านไป (หลังจากดำเนินการประมาณ 1 วัน) ประเภทการรอที่เกิดขึ้นมากที่สุดในฐานข้อมูลคือ CXPACKET (67%) และ OLEDB (17%) ถึงแม้ว่าเวลารอเฉลี่ยของแต่ละคนจะไม่นาน ฉันยังสังเกตเห็นว่าคำสั่งที่รันนานกว่าที่ระบุบน SQL Profiler เป็นการเรียกโพรซีเดอร์ที่เก็บไว้ซึ่งส่งคืนมากกว่าหนึ่ง resultset (มักจะ 3) มีปัญหาเกี่ยวกับอัมพาตที่นี่ได้ไหม? มีวิธีใดที่ฉันสามารถลองระบุได้ว่าเป็นสาเหตุของปัญหาหรือไม่
- ฉันได้อ่านบางที่ OLEDB รออาจเกิดจากการโทรไปยังทรัพยากร OLEDB เช่นเซิร์ฟเวอร์ที่เชื่อมโยง เรามีเซิร์ฟเวอร์ที่เชื่อมโยงเพื่อเชื่อมต่อกับเครื่องทำดัชนีบริการ (MSIDXS) อย่างไรก็ตามไม่มีคำสั่งใดที่ระบุว่าใช้งานได้นานใช้ประโยชน์จากเซิร์ฟเวอร์ที่เชื่อมโยงนั้น
- เวลารอเฉลี่ยที่สูงขึ้นที่ฉันมีสำหรับประเภทรอ LCK_M_X (เฉลี่ย 1.5 วินาที) แต่การรอประเภทนี้ไม่เกิดขึ้นบ่อยนักเมื่อเทียบกับประเภทอื่น ๆ (ตัวอย่างเช่น 64 LCK_M_X รอ vs 10,823 CXPACKET รอในช่วงเวลาเดียวกัน )
- สิ่งหนึ่งที่ฉันสังเกตเห็นคือบริการ MSDTC ไม่ได้เป็นกลุ่ม บริการ SQL Server ถูกทำคลัสเตอร์ แต่ไม่ใช่ MSDTC จะมีการเข้าชมการทำงานเนื่องจากเหตุนี้หรือไม่ เรากำลังใช้ MSDTC เพราะแอปของเราใช้ Enterprise Services (DCOM) เพื่อเข้าถึงฐานข้อมูล แต่เซิร์ฟเวอร์ไม่ได้ติดตั้งและกำหนดค่าโดยเรา แต่ลูกค้าของเรา
ทุกคนสามารถช่วยฉันทำความเข้าใจข้อมูลนี้ได้มากขึ้นไหม? ใครช่วยให้ฉันเข้าใจสิ่งที่อาจเกิดขึ้นได้บ้าง มีบางอย่างที่ฉันสามารถทำได้บนเซิร์ฟเวอร์เพื่อลองและคิดออก ฉันควรพูดคุยกับทีมพัฒนาแอปพลิเคชันหรือไม่
exec()
ฟังก์ชั่นจะอธิบายพฤติกรรมที่สังเกตได้ ในกรณีนี้การใช้งานsp_executesql
ตามปกติจะช่วยแก้ไขปัญหาเกี่ยวกับคำสั่ง SQL แบบไดนามิก