อินสแตนซ์แปลกของ SQL Server ขัดข้องเมื่อแคสต์เป็นตัวเลข


20

ในขณะที่ทำงานกับ C # Entity Framework ฉันสังเกตเห็นความผิดพลาดของอินสแตนซ์ SQL Server ของฉัน

ฉันสามารถติดตามข้อความนี้ได้:

SELECT * FROM dbo.[TestTable]
where mpnr in (1099059904,
1038139906,
1048119902,
1045119902,
1002109903,
1117109910,
1111149902,
1063149902,
1117159902,
1116109904,
1105079905,
1012079906,
1129129904,
1103059905,
1065059905,
1091059906,
1110149904,
1129149903,
1083029905,
1080139904,
1076109903,
1010019902,
1058019902,
1060019903,
1053019902,
1030089902,
1018149902,
1077149902,
1010109901,
1011109901,
1000119902,
1023049903,
1107119909,
1108119909,
1106119909)

ตารางมีลักษณะดังนี้:

CREATE TABLE dbo.[TestTable]([MPNR] [numeric](9, 0) NOT NULL)

ความผิดพลาดเกิดขึ้นทุกครั้งที่ฉันเริ่มการสืบค้น หากฉันลดจำนวนของค่าภายในส่วนINคำสั่งจะใช้งานได้ (ไม่ส่งคืนแถวแน่นอน)

ฉันทราบว่าค่าในINข้อเป็นตัวเลข 10 หลักและคอลัมน์มีเพียง 9 หลัก แต่ไม่ควรนำไปสู่ความผิดพลาดของอินสแตนซ์ของ SQL Server ทั้งหมด

เวอร์ชันของ SQL Server ของฉันคือ 2008 R2 บน Windows Server 2003 32 บิต

นี่เป็นข้อบกพร่องที่รู้จักหรือไม่? มี Patch สำหรับ SQL Server หรือไม่


ความคิดเห็นไม่ได้มีไว้สำหรับการอภิปรายเพิ่มเติม การสนทนานี้ได้รับการย้ายไปแชท
พอลไวท์พูดว่า GoFundMonica

คำตอบ:


20

ฉันสามารถทำซ้ำในปี 2008 R1 SP3 10.00.5512 แต่การติดตั้ง CU ล่าสุด (14) แก้ไข

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

การละเมิดการเข้าถึงเมื่อคุณเรียกใช้แบบสอบถามที่ประกอบด้วยค่าคงที่จำนวนมากในส่วนคำสั่ง IN ใน SQL Server 2008 หรือใน SQL Server 2012

ในขณะที่คุณอยู่บน 2008 R2 คุณจะต้องมี CU 9 เป็นอย่างต่ำสำหรับ SP1 หรือ CU 5 สำหรับ SP2

คำอธิบายอาการค่อนข้างสั้น แต่กล่าวถึงประเภทข้อมูลที่ไม่ตรงกัน

เมื่อคุณเรียกใช้แบบสอบถามที่ประกอบด้วยค่าคงที่จำนวนมากในส่วนคำสั่ง IN ใน Microsoft SQL Server 2008, Microsoft SQL Server 2012 หรือใน Microsoft SQL Server 2008 R2 การละเมิดการเข้าถึงอาจเกิดขึ้น

หมายเหตุเพื่อให้เกิดปัญหาค่าคงที่ในส่วนคำสั่ง IN ไม่สามารถจับคู่กับชนิดข้อมูลคอลัมน์ได้อย่างแม่นยำ

มันไม่ได้นิยาม "จำนวนมาก" จากการทดสอบฉันสงสัยว่านี่อาจหมายถึง "20 หรือมากกว่า" เนื่องจากนี่เป็นจุดตัดระหว่างสองวิธีที่แตกต่างกันในการประมาณค่าความเป็น cardinality

ความผิดพลาดที่เกิดขึ้นภายในไม่กี่วิธีที่เรียกว่าโดยCScaOp_In::FCalcSelectivity()มีชื่อเช่นและLoadHistogramFromXVariantArray()CInMemHistogram::FJoin() -> WalkHistograms()

สำหรับ 19 หรือน้อยกว่าที่แตกต่างกันในรายการรายการวิธีการเหล่านี้ไม่ได้ถูกเรียกเลย จุดบกพร่อง SQL Sever 2000 ที่คล้ายกันนี้ยังกล่าวถึงจุดตัดที่สำคัญเช่นกัน

การเติมตารางการทดสอบที่มี 100,000 ข้อมูลการทดสอบแบบสุ่มด้วยค่าระหว่าง 0 ถึง 1,047 และฮิสโตแกรมเริ่มต้นดังนี้

+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
|            0 |          0 |     104 |                   0 | 1              |
|            8 |        672 |     118 |                   7 | 96             |
|           13 |        350 |     118 |                   4 | 87.5           |
|           18 |        395 |     107 |                   4 | 98.75          |
|           23 |        384 |      86 |                   4 | 96             |
|           28 |        371 |      85 |                   4 | 92.75          |
+--------------+------------+---------+---------------------+----------------+

แบบสอบถาม

SELECT * FROM dbo.[TestTable]
where mpnr in (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19)
option (maxdop 1)

แสดงแถวโดยประมาณ 1856

นี่คือสิ่งที่คาดหวังจากการได้รับแถวที่ประมาณไว้สำหรับความเท่าเทียมกันทั้ง 19 ข้อและแยกกันเข้าด้วยกัน

+-------+----------------+-------+
| 1-7   | AVG_RANGE_ROWS | 96    |
| 8     | EQ_ROWS        | 118   |
| 9-12  | AVG_RANGE_ROWS | 87.5  |
| 13    | EQ_ROWS        | 118   |
| 14-17 | AVG_RANGE_ROWS | 98.75 |
| 18    | EQ_ROWS        | 107   |
| 19    | AVG_RANGE_ROWS | 96    |
+-------+----------------+-------+

7*96 + 118 + 4*87.5 + 118 + 4*98.75 + 107 + 1*96 = 1856

สูตรจะไม่ทำงานหลังจาก20ถูกเพิ่มลงในรายการใน (แถวโดยประมาณ1902.75แทนที่จะ1952เพิ่ม96เข้าไปในผลรวมจะสร้าง)

BETWEEN ดูเหมือนว่าจะใช้วิธีการอื่นในการคำนวณค่าประมาณของ cardinality

where mpnr BETWEEN 1 AND 20ประมาณเพียง 1,829.6 แถว ฉันไม่รู้ว่ามันมาจากฮิสโตแกรมที่แสดง

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