แบบสอบถามที่เรียกใช้แตกต่างกันใน SQL 2005 กับ SQL 2008R2


9

ที่สำนักงานของฉันเรามีข้อความค้นหาที่น่าเกลียด แต่ทำงานได้ค่อนข้างดีในการผลิตและในสภาพแวดล้อมการพัฒนา (20 วินาทีและ 4sec ตามลำดับ) อย่างไรก็ตามในสภาพแวดล้อมการทดสอบของเราใช้เวลามากกว่า 4 ชั่วโมง SQL2005 (+ แพตช์ล่าสุด) กำลังทำงานในการผลิตและการพัฒนา SQL2008R2 กำลังทำงานในการทดสอบ

ฉันดูที่ Query Plan และมันแสดงให้เห็นว่า SQL2008R2 กำลังใช้ TempDB โดย Table Spool (lazy spool) เพื่อจัดเก็บแถวที่ส่งคืนจากลิงก์เซิร์ฟเวอร์ ขั้นตอนต่อไปคือการแสดงลูปซ้อน (ซ้ายกึ่งต่อต้านเข้าร่วม) ขณะที่กินแบบสอบถามถึง 96.3% เส้นแบ่งระหว่างตัวดำเนินการทั้งสองอยู่ที่ 5,398MB!

แผนแบบสอบถามสำหรับ SQL 2005 ไม่แสดงการใช้ tempdb และไม่ใช้ Left Anti Semi Join

ด้านล่างนี้คือรหัสที่ถูกสุขอนามัยและการดำเนินการตามแผนในปี 2005 ด้านบนคือ 2008R2 ด้านล่าง

อะไรเป็นสาเหตุให้เกิดการเปลี่ยนแปลงอย่างรุนแรงและช้าลง? ฉันคาดหวังว่าจะเห็นแผนการดำเนินการที่แตกต่างกันดังนั้นมันจึงไม่รบกวนฉัน การชะลอตัวลงอย่างมากในเวลาสอบถามคือสิ่งที่ฉันมีปัญหา

ฉันต้องดูฮาร์ดแวร์พื้นฐานเนื่องจากรุ่น 2008R2 กำลังใช้ tempdb ฉันต้องดูที่วิธีเพิ่มประสิทธิภาพการใช้งานของมัน

มีวิธีที่ดีกว่าในการเขียนแบบสอบถามหรือไม่

ขอบคุณสำหรับความช่วยเหลือ

    INSERT INTO Table1_GroupLock (iGroupID, dLockedDate)
SELECT 
 Table1.iGroupID,
 GETDATE()
FROM Table1
WHERE 
 NOT EXISTS (
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE 
   (
    Alias2.FirstName + Alias2.LastName = dbo.fnRemoveNonLetter(Table1.FullName)
    AND NOT dbo.fnRemoveNonLetter(Table1.FullName) IS NULL
    AND NOT Alias2.FirstName IS NULL 
    AND NOT Alias2.LastName  IS NULL
   ) OR (
    Alias2.FamilyName = dbo.fnRemoveNonLetter(Table1.FamilyName)
    AND Alias2.Child1Name = dbo.fnRemoveNonLetter(Table1.Child1Name)
    AND NOT dbo.fnRemoveNonLetter(Table1.FamilyName) IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.Child1Name) IS NULL
    AND NOT Alias2.Familyname IS NULL
    AND NOT Alias2.Child1Name IS NULL
   ) OR (
    Alias2.StepFamilyName = dbo.fnRemoveNonLetter(Table1.StepFamilyName)
    AND Alias2.StepFamilyNameChild1 = dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2)
    AND NOT Alias2.StepFamilyName IS NULL
    AND NOT Alias2.StepFamilyNameChild1 IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyName) IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2) IS NULL
   )  
 ) AND NOT EXISTS (
  SELECT 1
  FROM Table3
  INNER JOIN Table4
   ON Table4.FirstNameType = Table3.FirstNameType 
  INNER JOIN table5
   ON table5.LastNameType = Table3.LastNameType 
  WHERE 
   Table3.iGroupID = Table1.iGroupID
   AND Table3.bIsClosed = 0
   AND Table4.sNameTypeConstant = 'new_lastname'
   AND table5.sFirstNameConstant = 'new_firstname'
 )

SQL-2005


SQL2008R2

:: แก้ไข :: ดำเนินการแบบสอบถามจากอินสแตนซ์ SQL2005 ที่แตกต่างกันค่อนข้างมากแผนการดำเนินการเช่นเดียวกับ "ดีหนึ่ง" ยังไม่แน่ใจว่ารุ่น 2005 สองรุ่นทำงานอย่างไรกับเซิร์ฟเวอร์ที่เชื่อมโยง 2008R2 ได้ดีกว่าอินสแตนซ์ 2008R2 กับอินสแตนซ์ 2008R2

ในขณะที่ฉันไม่ปฏิเสธว่ารหัสสามารถใช้งานบางอย่างได้ แต่ถ้าเป็นปัญหาที่เกิดขึ้นกับรหัสฉันจะไม่เห็นแผน exec เดียวกันนี้ตลอดการทดลองทั้งหมดของฉันหรือไม่ ไม่ว่าจะเป็นเวอร์ชั่น SQL หรือไม่?

:: แก้ไข :: ฉันใช้ SP1 และ CU3 กับทั้งสองอินสแตนซ์ 2008R2 แล้วยังไม่มีลูกเต๋า ฉันได้ตั้งค่าการจัดวางเฉพาะในเซิร์ฟเวอร์ที่เชื่อมโยงโดยไม่มีลูกเต๋า ฉันได้ตั้งค่าการอนุญาตโดยเฉพาะสำหรับผู้ใช้ของฉันให้เป็นดูแลระบบทั้งสองกรณีไม่มีลูกเต๋า ฉันยังจำภายใน sql server 2008 internals และการแก้ไขปัญหาเราจะดูว่าฉันสามารถติดตามสิ่งนี้ได้อย่างไร

ขอบคุณทุกคนสำหรับความช่วยเหลือและเคล็ดลับ

:: แก้ไข :: ฉันทำการเปลี่ยนแปลงสิทธิ์ต่าง ๆ ไปยังเซิร์ฟเวอร์ที่เชื่อมโยงแล้ว ฉันใช้การเข้าสู่ระบบ SQL, การเข้าสู่ระบบโดเมน, ฉันมีผู้ใช้ที่ได้รับการเลียนแบบ, ฉันได้ใช้ตัวเลือก "ถูกสร้างขึ้นโดยใช้บริบทความปลอดภัยนี้" ฉันสร้างผู้ใช้ทั้งสองด้านของเซิร์ฟเวอร์ที่เชื่อมโยงซึ่งมีสิทธิ์ดูแลระบบบนเซิร์ฟเวอร์ ฉันไม่มีความคิด

ฉันยังอยากรู้ว่าทำไม SQL2005 จึงเรียกใช้งานแบบสอบถามจึงแตกต่างอย่างมากจาก SQL2008R2 ถ้ามันเป็นแบบสอบถามที่ไม่ดีฉันจะเห็นเวลารันไทม์ 4 + ชม. ทั้ง SQL2005 และ SQL2008R2

คำตอบ:


5

ฉันต้องการให้คุณทำงานซ้ำแบบสอบถาม

คุณมีปัญหาเรื่องความสามารถในการ sargability และแม้กระทั่งการใช้ฟังก์ชันสเกลาร์ในที่นั่น คุณอาจต้องการสร้างคอลัมน์ที่คำนวณแบบ FullName บน Table2 และวางดัชนีไว้บนนั้นตรวจสอบให้แน่ใจว่าดัชนีของคุณรวมถึงชื่อและนามสกุล คุณควรเพิ่มดัชนีที่ช่วยให้อื่น ๆ

นอกจากนี้ให้สร้างฟังก์ชันที่มีค่าเป็นตารางแบบอินไลน์เพื่อทำหน้าที่ "RemoveNonLetter" ของคุณและทำซ้ำแบบสอบถามของคุณเพื่อใช้งานนั้นอาจใช้ APPLY ตามที่ฉันทำไว้ที่นี่

และตรวจสอบข้อผิดพลาดที่คำตอบของ Paul อ้างถึงอย่างแน่นอน

INSERT INTO Table1_GroupLock (iGroupID, dLockedDate)
SELECT 
 Table1.iGroupID,
 GETDATE()
FROM Table1
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.FullName)) AS fn (FullName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.FamilyName)) AS famn (FamilyName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.Child1Name)) AS c1n (Child1Name)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.StepFamilyName)) AS sfn (StepFamilyName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.StepFamilyNameChild2)) AS sfnc2 (StepFamilyNameChild2)
WHERE 
 NOT EXISTS (
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.FullName = fn.FullName
  UNION ALL
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.FamilyName = famn.FamilyName AND Alias2.Child1Name = c1n.Child1Name
  UNION ALL
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.StepFamilyName = sfn.StepFamilyName AND Alias2.StepFamilyNameChild1 = sfnc2.StepFamilyNameChild2
 ) 
 AND NOT EXISTS (
  SELECT 1
  FROM Table3
  INNER JOIN Table4
   ON Table4.FirstNameType = Table3.FirstNameType 
  INNER JOIN table5
   ON table5.LastNameType = Table3.LastNameType 
  WHERE 
   Table3.iGroupID = Table1.iGroupID
   AND Table3.bIsClosed = 0
   AND Table4.sNameTypeConstant = 'new_lastname'
   AND table5.sFirstNameConstant = 'new_firstname'
 )
;

6

การเพิ่มคำตอบก่อนหน้านี้สาเหตุของการถดถอยแผนอาจเกิดจากข้อผิดพลาดในการประมาณค่า cardinality ที่ทราบเมื่อแผนรวมการเข้าร่วมกึ่งต่อต้าน ดูKB 2222998

สมมติว่าแผนปี 2005 ให้ประสิทธิภาพที่ยอมรับได้คุณอาจพบว่าการนำเซิร์ฟเวอร์มาสู่เวอร์ชันที่มีการแก้ไขนั้น (และการเปิดใช้งาน TF4199 เพื่อเปิดใช้งาน) จะทำให้คุณกลับสู่แผน 'ดี'

ที่กล่าวว่ามีโอกาสอื่น ๆ อีกมากมายที่จะปรับปรุงการค้นหานี้ดังนั้นจึงอาจเป็นเวลาที่ดีที่จะมีสมาธิในการทำสิ่งนั้นแทน


5

ฉันขอแนะนำว่าข้อมูลระยะไกลถูกเก็บพักในเครื่องเนื่องจากหนึ่งใน

  1. การตั้งค่าเซิร์ฟเวอร์ที่เชื่อมโยง (เช่นการเปรียบเทียบ) ไม่เหมือนกัน
  2. การจัดเรียงโลคัลไม่เหมือนกับรีโมตแม้ว่าการตั้งค่าเซิร์ฟเวอร์ที่เชื่อมโยง
  3. การสืบค้นไม่สามารถทำงานได้อย่างถูกต้องจากระยะไกลเนื่องจากการอนุญาต

สำหรับจุดที่ 1 ให้ดูที่sp_serveroption
และสำหรับจุดที่ 2 แต่ตรวจสอบการเปรียบเทียบเซิร์ฟเวอร์ / db ด้วย

สำหรับจุด 3 ดูสิ่งเหล่านี้จาก Linchi Shea:

คุณกำลังขอให้ SQL Server ประมวลผลข้อมูลทั้งหมดในเครื่องตามคำตอบของฉันที่นี่: ผลกระทบของการใช้ OPENQUERY ในมุมมอง

แก้ไข

จากการดูครั้งที่สองฉันเห็นการโทรทางไกล 2 ครั้งในแผน "ดี" มากกว่าหนึ่งสาย นี่เป็นการยืนยันสิ่งที่ฉันพูดที่นี่


ขออภัยในความล่าช้าที่ยาวนาน 1: ฉันตรวจสอบการตั้งค่าเซิร์ฟเวอร์ที่เชื่อมโยงพวกเขาเหมือนกัน 2: ฉันยังตรวจสอบและตั้งค่าการเปรียบเทียบคุณสมบัติเซิร์ฟเวอร์ที่เชื่อมโยงกับเซิร์ฟเวอร์ระยะไกลโดยปริยาย 3: บริบทความปลอดภัยฉันยังคงทำการทดสอบ A / B ฉันยังคงหัวแข็งในตรรกะที่อยู่เบื้องหลังแผนการบริหารที่แตกต่างกันอย่างมาก จากเซิร์ฟเวอร์ R2 ไปยังเซิร์ฟเวอร์ R2 เป็นเพียงการเรียกใช้ตัวเลือก (ดึงเข้าแถวมากกว่า 150K) จากนั้นจึงทำการเชื่อมต่อ ในกรณีที่เป็น 2005 ถึง R2 จะทำการเลือกและเข้าร่วมบนเซิร์ฟเวอร์ระยะไกล บริบทความปลอดภัยสำหรับสถานการณ์ทั้งสองเหมือนกัน
RateControl

3

+1 ที่ลองเขียนความคิดเห็นแบบสอบถามของคุณจาก datagod

ฉันยังสงสัยว่าคุณกำลังเจอปัญหาสิทธิ์ในฝั่งเซิร์ฟเวอร์ที่เชื่อมโยงซึ่งนำไปสู่การชะลอตัวนี้หรือไม่ ฉัน blogged เกี่ยวกับการชะลอตัวเซิร์ฟเวอร์ที่เชื่อมโยงนี้สักครู่แล้ว อาจมีค่าในการตรวจสอบ perms (มันเป็นเซิร์ฟเวอร์ที่เชื่อมโยงกับ SQL หรือไม่หรือเป็นอีกหนึ่ง DBMS หรือไม่ถ้าหลังคุณก็จะไม่ได้รับสถิติที่ยอดเยี่ยมเลย)

คุณมี SQL Server 2005 ในสภาพแวดล้อมการทดสอบยังคงลองใช้แบบสอบถามนี้และแยกแยะสภาพแวดล้อมหรือไม่

คุณสร้างสถิติขึ้นใหม่ตั้งแต่อัปเกรดหรือไม่


3

มีปัญหามากมายกับการเปรียบเทียบนี้ ... ฉันแค่ไม่รู้ว่าจะเริ่มจากตรงไหน

  1. รับข้อมูลจำเพาะที่แน่นอนสำหรับการผลิตและเครื่องทดสอบของคุณ

  2. กำหนดลิงก์เครือข่ายระหว่าง severs ที่เชื่อมโยงต่างๆในสภาพแวดล้อมทั้งสอง พวกเขามีความเร็วเท่ากันหรือไม่ เซิร์ฟเวอร์ตั้งอยู่ข้างกันในสภาพแวดล้อมทั้งสองหรือไม่?

  3. มีวิธีใดบ้างไหมที่คุณสามารถเขียนแบบสอบถามซ้ำเพื่อไม่ใช้เซิร์ฟเวอร์ที่เชื่อมโยงได้ การเข้าร่วมตารางทั่วทั้งเซิร์ฟเวอร์ทำให้คุณเสี่ยงต่อการเปลี่ยนแปลงโทโปโลยีและเขาส่วนใหญ่ช้ามาก

  4. โดยทั่วไปแล้วการใช้ NOT และ OR จะนำไปสู่การสแกนเต็มตาราง ลองเขียนแบบสอบถามใหม่

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