ฉันพยายามวินิจฉัยช้าลงในแอปพลิเคชัน สำหรับสิ่งนี้ฉันได้บันทึกกิจกรรมเพิ่มเติมของ SQL Server แล้ว
- สำหรับคำถามนี้ฉันกำลังดูขั้นตอนการจัดเก็บเฉพาะอย่างใดอย่างหนึ่ง
- แต่มีชุดหลักของขั้นตอนการจัดเก็บโหลที่เท่ากันสามารถใช้เป็นการสอบสวนแอปเปิ้ลแอปเปิ้ล
- และเมื่อใดก็ตามที่ฉันเรียกใช้หนึ่งในกระบวนงานที่เก็บไว้ด้วยตนเองมันจะทำงานได้อย่างรวดเร็วเสมอ
- และหากผู้ใช้ลองอีกครั้งมันจะทำงานเร็ว
เวลาดำเนินการของโพรซีเดอร์ที่เก็บแตกต่างกันไป การประมวลผลของโพรซีเดอร์ที่เก็บไว้นี้ส่งคืนเป็นจำนวนมากใน <1s:
และสำหรับถัง"เร็ว"นั้นมันน้อยกว่า 1 วินาทีมาก จริง ๆ แล้วประมาณ 90 ms:
แต่มีหางยาวของผู้ใช้ที่ต้องรอ 2 วินาที, 3 วินาที, 4s วินาที บางคนต้องรอ 12 วินาที, 13 วินาที, 14 วินาที จากนั้นก็มีวิญญาณที่น่าสงสารจริงๆที่ต้องรอ 22s, 23s, 24s
และหลังจาก 30s, โปรแกรมไคลเอนต์ให้ขึ้นยกเลิกแบบสอบถามและผู้ใช้ต้องรอ30 วินาที
สหสัมพันธ์เพื่อค้นหาสาเหตุ
ดังนั้นฉันจึงพยายามที่จะมีความสัมพันธ์:
- ระยะเวลาและตรรกะอ่าน
- ระยะเวลาเทียบกับการอ่านทางกายภาพ
- ระยะเวลาเทียบกับเวลา cpu
และดูเหมือนจะไม่มีความสัมพันธ์ใด ๆ ; ดูเหมือนจะไม่มีสาเหตุ
ระยะเวลาและตรรกะอ่าน : ไม่ว่าจะเป็นเล็ก ๆ น้อย ๆ หรือจำนวนมากอ่านตรรกะระยะเวลายังคงผันผวน :
ระยะเวลาและการอ่านทางกายภาพ : แม้ว่าการสืบค้นจะไม่ได้รับบริการจากแคชและจำเป็นต้องมีการอ่านจำนวนมาก แต่จะไม่ส่งผลต่อระยะเวลา:
ระยะเวลาเทียบกับเวลาของ cpu : ไม่ว่าแบบสอบถามจะใช้เวลา 0 วินาทีของ CPU หรือเต็ม 2.5s ของเวลา CPU ระยะเวลามีความแปรปรวนเท่ากัน
โบนัส : ฉันสังเกตว่าระยะเวลา v การอ่านทางกายภาพและระยะเวลา v เวลา CPUดูคล้ายกันมาก นี่เป็นการพิสูจน์ว่าฉันพยายามเชื่อมโยงเวลาของ CPU กับการอ่านแบบฟิสิคัล:
ปรากฎว่าการใช้งาน CPU จำนวนมากมาจาก I / O ใครจะรู้!
ดังนั้นหากไม่มีอะไรเกี่ยวกับการดำเนินการสืบค้นที่สามารถอธิบายความแตกต่างในเวลาดำเนินการนั่นหมายความว่าเป็นสิ่งที่ไม่เกี่ยวข้องกับ CPU หรือฮาร์ดไดรฟ์หรือไม่
หาก CPU หรือฮาร์ดไดรฟ์เป็นคอขวด มันจะไม่ใช่คอขวดเหรอ?
ถ้าเราตั้งสมมติฐานว่ามันเป็นซีพียูที่เป็นคอขวด CPU นั้นใช้พลังงานน้อยสำหรับเซิร์ฟเวอร์นี้:
- ถ้าเช่นนั้นการประมวลผลโดยใช้เวลา CPU จะใช้เวลานานกว่าหรือไม่
- เนื่องจากพวกเขาต้องทำกับผู้อื่นโดยใช้ซีพียูที่โอเวอร์โหลด?
ในทำนองเดียวกันสำหรับฮาร์ดไดรฟ์ หากเราตั้งสมมติฐานว่าฮาร์ดไดรฟ์เป็นคอขวด ฮาร์ดไดรฟ์มีการสุ่มใส่พอสำหรับเซิร์ฟเวอร์นี้ไม่เพียงพอ:
- ถ้าอย่างนั้นการประหารชีวิตโดยใช้การอ่านเชิงกายภาพจะใช้เวลานานกว่ากันไหม?
- เนื่องจากพวกเขาต้องทำกับผู้อื่นโดยใช้ I / O ฮาร์ดไดรฟ์ที่โอเวอร์โหลด
ขั้นตอนการจัดเก็บตัวเองไม่ได้ดำเนินการหรือต้องมีการเขียน
- โดยปกติแล้วจะส่งคืน 0 แถว (90%)
- บางครั้งมันจะส่งคืน 1 แถว (7%)
- มันจะกลับมา 2 แถว (1.4%)
- และในกรณีที่เลวร้ายที่สุดมันส่งคืนมากกว่า 2 แถว (ครั้งเดียวส่งคืน 12 แถว)
ดังนั้นจึงไม่เหมือนกับว่าจะส่งคืนปริมาณข้อมูลที่บ้า
การใช้งาน CPU ของเซิร์ฟเวอร์
ค่าเฉลี่ยการใช้งานตัวประมวลผลของเซิร์ฟเวอร์ประมาณ 1.8% โดยมีการขัดขวางเป็นครั้งคราวสูงถึง 18% - ดังนั้นจึงไม่ดูเหมือนว่า CPU จะมีปัญหา:
ดังนั้นเซิร์ฟเวอร์ CPU จึงดูไม่โอเวอร์โหลด
แต่เซิร์ฟเวอร์เป็นเสมือน ...
มีอะไรนอกจักรวาล?
สิ่งเดียวที่เหลือที่ฉันจินตนาการได้ก็คือสิ่งที่อยู่นอกจักรวาลของเซิร์ฟเวอร์
- ถ้ามันไม่ใช่ตรรกะอ่าน
- และมันไม่ใช่การอ่านทางกายภาพ
- และไม่ใช่การใช้งาน cpu
- และไม่ใช่โหลดซีพียู
และไม่เหมือนว่ามันเป็นพารามิเตอร์ของกระบวนงานที่เก็บไว้ (เนื่องจากการออกแบบสอบถามเดียวกันด้วยตนเองและไม่ใช้เวลา 27 วินาที - ใช้เวลา ~ 0 วินาที)
สิ่งใดที่บัญชีสำหรับเซิร์ฟเวอร์บางครั้งใช้เวลา 30 วินาทีแทนที่จะเป็น 0 วินาทีเพื่อเรียกใช้ขั้นตอนการจัดเก็บที่รวบรวมไว้แบบเดียวกัน
- ด่าน?
มันเป็นเซิร์ฟเวอร์เสมือน
- โฮสต์โอเวอร์โหลดหรือไม่
- VM อื่นบนโฮสต์เดียวกัน
การผ่านเหตุการณ์ที่เพิ่มขึ้นของเซิร์ฟเวอร์ ไม่มีสิ่งใดเกิดขึ้นเป็นพิเศษเมื่อแบบสอบถามใช้เวลา 20 วินาที มันทำงานได้ดีจากนั้นตัดสินใจไม่ทำงาน:
- 2 วินาที
- 1 วินาที
- 30 วินาที
- 3 วินาที
- 2 วินาที
และไม่มีรายการอื่น ๆ ที่ยากเย็นแสนเข็ญที่ฉันสามารถหาได้ ไม่ใช่ระหว่างการสำรองข้อมูลบันทึกธุรกรรมทุก 2 ชั่วโมง
สิ่งที่คนอื่นอาจจะเป็น?
มีอะไรที่ฉันสามารถพูดได้นอกเหนือจาก: "เซิร์ฟเวอร์"หรือไม่?
แก้ไข : สัมพันธ์ตามเวลาของวัน
ฉันรู้ว่าฉันมีความสัมพันธ์กับระยะเวลาทุกอย่าง:
- ตรรกะอ่าน
- อ่านทางกายภาพ
- การใช้ซีพียู
แต่สิ่งหนึ่งที่ฉันไม่ได้มีความสัมพันธ์มันจะเป็นช่วงเวลาของวัน บางทีการสำรองข้อมูลบันทึกธุรกรรมทุก 2 ชั่วโมงอาจเป็นปัญหา
หรือบางทีอาจจะชะลอตัวไม่เกิดขึ้นในระหว่างการ chucks ด่าน?
Nope:
Intel Xeon Gold Quad-core 6142
แก้ไข - ผู้คนกำลังตั้งสมมติฐานแผนการดำเนินการแบบสอบถาม
ผู้คนกำลังตั้งสมมติฐานว่าแผนการดำเนินการแบบสอบถามจะต้องแตกต่างกันระหว่าง "เร็ว" และ "ช้า" พวกเขาจะไม่.
และเราสามารถเห็นสิ่งนี้ได้ทันทีจากการตรวจสอบ
เรารู้ว่าระยะเวลาคำถามที่นานขึ้นนั้นไม่ใช่เพราะแผนการดำเนินการ "ไม่ดี":
- หนึ่งที่อ่านตรรกะมากขึ้น
- อันที่ใช้ CPU มากขึ้นจากการรวมมากขึ้นและการค้นหาคีย์
เพราะหากการเพิ่มขึ้นของการอ่านหรือการเพิ่มขึ้นของ CPU เป็นสาเหตุของระยะเวลาการสืบค้นที่เพิ่มขึ้นเราจะเห็นแล้วว่าข้างต้น ไม่มีความสัมพันธ์กัน
แต่ให้ลองเชื่อมโยงช่วงเวลากับตัวชี้วัดพื้นที่อ่าน CPU:
มีความสัมพันธ์น้อยลง - ซึ่งเป็นความขัดแย้ง
แก้ไข : อัปเดตแผนภาพกระจายเพื่อแก้ไขข้อบกพร่องในแปลงกระจาย Excel ที่มีค่าจำนวนมาก
ขั้นตอนถัดไป
ขั้นตอนต่อไปของฉันคือการรับคนที่จะต้องเซิร์ฟเวอร์สร้างกิจกรรมสำหรับแบบสอบถามที่ถูกบล็อก - หลังจาก 5 วินาที:
EXEC sp_configure 'blocked process threshold', '5';
RECONFIGURE
มันจะไม่อธิบายหากเคียวรีถูกบล็อคเป็นเวลา4วินาที แต่บางทีทุกอย่างที่บล็อกข้อความค้นหาเป็นเวลา 5 วินาทีก็บล็อกบางอย่างเป็นเวลา 4 วินาที
แผนช้า
นี่คือแผนช้าของทั้งสองโพรซีเดอร์ที่เก็บไว้ซึ่งถูกเรียกใช้งาน:
- `EXECUTE FindFrob @CustomerID = 7383, @StartDate = '20190725 04: 00: 00.000', @EndDate = '20190726 04: 00: 00.000'
- `EXECUTE FindFrob @CustomerID = 7383, @StartDate = '20190725 04: 00: 00.000', @EndDate = '20190726 04: 00: 00.000'
โพรซีเดอร์ที่เก็บไว้แบบเดียวกันโดยมีพารามิเตอร์เดียวกันรันกลับไปด้านหลัง:
| Duration (us) | CPU time (us) | Logical reads | Physical reads |
|---------------|---------------|---------------|----------------|
| 13,984,446 | 47,000 | 5,110 | 771 |
| 4,603,566 | 47,000 | 5,126 | 740 |
โทร 1:
|--Nested Loops(Left Semi Join, OUTER REFERENCES:([Contoso2].[dbo].[Frobs].[FrobGUID]) OPTIMIZED)
|--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]))
| |--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[RowNumber]) OPTIMIZED)
| | |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
| | | |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
| | | | |--Index Seek(OBJECT:([Contoso2].[dbo].[TransactionPatronInfo].[IX_TransactionPatronInfo_CustomerID_TransactionGUID] AS [tpi]), SEEK:([tpi].[CustomerID]=[@CustomerID]) ORDERED FORWARD)
| | | | |--Index Seek(OBJECT:([Contoso2].[dbo].[Transactions].[IX_Transactions_TransactionGUIDTransactionDate]), SEEK:([Contoso2].[dbo].[Transactions].[TransactionGUID]=[Contoso2].[dbo
| | | |--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions2_MoneyAppearsOncePerTransaction]), SEEK:([Contoso2].[dbo].[FrobTransactions].[TransactionGUID]=[Contos
| | |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions_RowNumber]), SEEK:([Contoso2].[dbo].[FrobTransactions].[RowNumber]=[Contoso2].[dbo].[Fin
| |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[Frobs].[PK_Frobs_FrobGUID]), SEEK:([Contoso2].[dbo].[Frobs].[FrobGUID]=[Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]), WHERE:([Contos
|--Filter(WHERE:([Expr1009]>(1)))
|--Compute Scalar(DEFINE:([Expr1009]=CONVERT_IMPLICIT(int,[Expr1012],0)))
|--Stream Aggregate(DEFINE:([Expr1012]=Count(*)))
|--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactins_OnFrobGUID]), SEEK:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]=[Contoso2].[dbo].[Frobs].[LC
โทร 2
|--Nested Loops(Left Semi Join, OUTER REFERENCES:([Contoso2].[dbo].[Frobs].[FrobGUID]) OPTIMIZED)
|--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]))
| |--Nested Loops(Inner Join, OUTER REFERENCES:([Contoso2].[dbo].[FrobTransactions].[RowNumber]) OPTIMIZED)
| | |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
| | | |--Nested Loops(Inner Join, OUTER REFERENCES:([tpi].[TransactionGUID]) OPTIMIZED)
| | | | |--Index Seek(OBJECT:([Contoso2].[dbo].[TransactionPatronInfo].[IX_TransactionPatronInfo_CustomerID_TransactionGUID] AS [tpi]), SEEK:([tpi].[CustomerID]=[@CustomerID]) ORDERED FORWARD)
| | | | |--Index Seek(OBJECT:([Contoso2].[dbo].[Transactions].[IX_Transactions_TransactionGUIDTransactionDate]), SEEK:([Contoso2].[dbo].[Transactions].[TransactionGUID]=[Contoso2].[dbo
| | | |--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions2_MoneyAppearsOncePerTransaction]), SEEK:([Contoso2].[dbo].[FrobTransactions].[TransactionGUID]=[Contos
| | |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactions_RowNumber]), SEEK:([Contoso2].[dbo].[FrobTransactions].[RowNumber]=[Contoso2].[dbo].[Fin
| |--Clustered Index Seek(OBJECT:([Contoso2].[dbo].[Frobs].[PK_Frobs_FrobGUID]), SEEK:([Contoso2].[dbo].[Frobs].[FrobGUID]=[Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]), WHERE:([Contos
|--Filter(WHERE:([Expr1009]>(1)))
|--Compute Scalar(DEFINE:([Expr1009]=CONVERT_IMPLICIT(int,[Expr1012],0)))
|--Stream Aggregate(DEFINE:([Expr1012]=Count(*)))
|--Index Seek(OBJECT:([Contoso2].[dbo].[FrobTransactions].[IX_FrobTransactins_OnFrobGUID]), SEEK:([Contoso2].[dbo].[FrobTransactions].[OnFrobGUID]=[Contoso2].[dbo].[Frobs].[LC
มันสมเหตุสมผลสำหรับแผนการที่จะเหมือนกัน มันกำลังดำเนินการขั้นตอนการจัดเก็บเดียวกันกับพารามิเตอร์เดียวกัน