ตามที่ระบุไว้แล้วในความคิดเห็นดูเหมือนว่าคุณจำเป็นต้องปรับปรุงสถิติของคุณ
จำนวนแถวโดยประมาณที่มาจากการเข้าร่วมระหว่างlocation
และtestruns
แตกต่างกันอย่างมากระหว่างสองแผน
เข้าร่วมประมาณการแผน: 1
ประมาณการแผนแบบสอบถามย่อย: 8,748
จำนวนแถวที่แท้จริงจากการเข้าร่วมคือ 14,276
แน่นอนว่าไม่มีเหตุผลใด ๆ ที่เข้าใจง่ายว่ารุ่นเข้าร่วมควรประมาณว่า 3 แถวควรมาจากlocation
และสร้างแถวเข้าร่วมเดียวในขณะที่แบบสอบถามย่อยประมาณว่าแถวเดียวจะสร้าง 8,748 จากการเข้าร่วมเดียวกัน แต่อย่างไรก็ตามฉันก็สามารถ เพื่อทำซ้ำสิ่งนี้
สิ่งนี้ดูเหมือนว่าจะเกิดขึ้นหากไม่มีการข้ามระหว่างฮิสโตแกรมเมื่อสร้างสถิติ เวอร์ชันเข้าร่วมถือว่าเป็นแถวเดียว และการค้นหาความเท่าเทียมกันครั้งเดียวของเคียวรีย่อยจะถือว่าแถวที่ประมาณไว้เหมือนกันกับการค้นหาความเท่าเทียมกันกับตัวแปรที่ไม่รู้จัก
cardinality ของ testruns 26244
คือ สมมติว่ามีประชากรพร้อมรหัสสถานที่แตกต่างกันสามรหัสดังนั้นแบบสอบถามต่อไปนี้จะประมาณว่า8,748
จะส่งคืนแถว ( 26244/3
)
declare @i int
SELECT *
FROM testruns AS tr
WHERE tr.location_id = @i
เนื่องจากตารางlocations
มีเพียง 3 แถวเท่านั้นจึงเป็นเรื่องง่าย (ถ้าเราไม่มีคีย์ต่างประเทศ) เพื่อสร้างสถานการณ์ที่มีการสร้างสถิติจากนั้นข้อมูลจะถูกเปลี่ยนแปลงในลักษณะที่ส่งผลกระทบต่อจำนวนแถวจริงที่ส่งคืน แต่กลับไม่เพียงพอ เดินทางไปที่การอัปเดตอัตโนมัติของสถิติและเกณฑ์การคอมไพล์ซ้ำ
ในขณะที่ SQL Server รับจำนวนแถวที่มาจากการเข้าร่วมนั้นดังนั้นการประมาณการแถวอื่น ๆ ทั้งหมดในแผนการเข้าร่วมจึงประเมินค่าต่ำเกินไป tempdb
เช่นเดียวกับความหมายที่คุณได้รับแผนอนุกรมแบบสอบถามยังได้รับทุนหน่วยความจำไม่เพียงพอและทุกประเภทและกัญชาเข้าร่วมการรั่วไหลไป
สถานการณ์หนึ่งที่เป็นไปได้ที่จะสร้างแถวจริงเทียบกับแถวโดยประมาณที่แสดงในแผนของคุณอยู่ด้านล่าง
CREATE TABLE location
(
id INT CONSTRAINT locationpk PRIMARY KEY,
location VARCHAR(MAX) /*From the separate filter think you are using max?*/
)
/*Temporary ids these will be updated later*/
INSERT INTO location
VALUES (101, 'Coventry'),
(102, 'Nottingham'),
(103, 'Derby')
CREATE TABLE testruns
(
location_id INT
)
CREATE CLUSTERED INDEX IX ON testruns(location_id)
/*Add in 26244 rows of data split over three ids*/
INSERT INTO testruns
SELECT TOP (5984) 1
FROM master..spt_values v1, master..spt_values v2
UNION ALL
SELECT TOP (5984) 2
FROM master..spt_values v1, master..spt_values v2
UNION ALL
SELECT TOP (14276) 3
FROM master..spt_values v1, master..spt_values v2
/*Create statistics. The location_id histograms don't intersect at all*/
UPDATE STATISTICS location(locationpk) WITH FULLSCAN;
UPDATE STATISTICS testruns(IX) WITH FULLSCAN;
/* UPDATE location.id. Three row update is below recompile threshold*/
UPDATE location
SET id = id - 100
จากนั้นการเรียกใช้คิวรีต่อไปนี้ให้ค่าความคลาดเคลื่อนที่เกิดขึ้นจริงเทียบกับค่าประมาณเดียวกัน
SELECT *
FROM testruns AS tr
WHERE tr.location_id = (SELECT id
FROM location
WHERE location = 'Derby')
SELECT *
FROM testruns AS tr
JOIN location loc
ON tr.location_id = loc.id
WHERE loc.location = ( 'Derby' )