สำหรับฉันดูเหมือนว่าwhere
ประโยคในแบบสอบถามกำลังให้ปัญหาและเป็นสาเหตุของการประมาณการที่ต่ำแม้ว่าOPTION(RECOMPILE)
จะถูกใช้
ฉันสร้างข้อมูลทดสอบและในที่สุดก็มาพร้อมกับโซลูชันสองวิธีจัดเก็บID
เขตข้อมูลจากresources
ตัวแปร (ถ้าเป็นค่าที่ไม่ซ้ำกัน) หรือตารางชั่วคราวหากเราสามารถมีมากกว่าหนึ่งID
ได้
บันทึกการทดสอบพื้นฐาน
SET NOCOUNT ON
DECLARE @i int= 1;
WHILE @i <= 10000
BEGIN
INSERT INTO [dbo].[Settings]([resourceId],[typeID],remark)
VALUES(@i,@i,'KEPT THESE VALUES OUT BECAUSE IT WOULD CLUTTER THE EXAMPLES, VALUES OVER 8000 Chars entered here'); -- 23254 character length on each value
INSERT INTO [dbo].[Resources](resourceUID)
VALUES(@i);
SET @i += 1;
END
แทรกค่า 'ค้นหา' เพื่อไปยังชุดผลลัพธ์โดยประมาณเช่นเดียวกับ OP (1300 บันทึก)
INSERT INTO [dbo].[Settings]([resourceId],[typeID],remark)
VALUES(38,38,'KEPT THESE VALUES OUT BECAUSE IT WOULD CLUTTER THE EXAMPLES, VALUES OVER 8000 Chars entered here')
GO 1300
เปลี่ยนสถิติที่เข้ากันได้และอัปเดตเพื่อให้ตรงกับ OP
ALTER DATABASE StackOverflow SET COMPATIBILITY_LEVEL = 120;
UPDATE STATISTICS settings WITH FULLSCAN;
UPDATE STATISTICS resources WITH FULLSCAN;
ข้อความค้นหาต้นฉบับ
exec sp_executesql N'
select r.id
FROM Resources r
inner join Settings on resourceid=r.id
where resourceUID=@UID
ORDER BY typeID',
N'@UID int',
@UID=38
ประมาณการของฉันยิ่งแย่ลงไปอีกโดยมีแถวที่ประมาณการไว้หนึ่งแถวขณะที่ส่งคืน 1300 และเช่นเดียวกับ OP ที่ระบุไว้มันไม่สำคัญว่าถ้าฉันเพิ่มOPTION(RECOMPILE)
สิ่งสำคัญที่ควรทราบคือเมื่อเรากำจัดส่วนที่ประมาณการประมาณถูกต้อง 100% ซึ่งคาดว่าเนื่องจากเราใช้ข้อมูลทั้งหมดในตารางทั้งสอง
ฉันบังคับดัชนีเพียงเพื่อให้แน่ใจว่าเราใช้ดัชนีเดียวกับในแบบสอบถามก่อนหน้าเพื่อพิสูจน์จุด
exec sp_executesql N'
select r.id,remark
FROM Resources r with(index([IX_UID]))
inner join Settings WITH(INDEX([IX_Test]))
on resourceid=r.id
ORDER BY typeID',
N'@UID int',
@UID=38
เป็นที่คาดหวังที่ดีประมาณการ
ดังนั้นสิ่งที่เราสามารถเปลี่ยนเพื่อรับประมาณการที่ดีขึ้น แต่ยังคงหาค่าของเรา?
IF @UID นั้นไม่เหมือนกันดังตัวอย่างใน OP ที่ให้มาเราสามารถใส่ single id
ที่ส่งคืนมาจากresources
ตัวแปรแล้วค้นหาตัวแปรนั้นด้วย OPTION (RECOMPILE)
DECLARE @UID int =38 , @RID int;
SELECT @RID=r.id from
Resources r where resourceUID = @UID;
SELECT @uid, remark
from Settings
where resourceId = @uid
Order by typeID
OPTION(RECOMPILE);
ซึ่งให้การประมาณการที่แม่นยำ 100%
แต่จะเกิดอะไรขึ้นถ้ามีหลาย resourceUID ในทรัพยากร
เพิ่มข้อมูลการทดสอบ
INSERT INTO Resources(ResourceUID)
VALUES (38);
go 50
อาจแก้ไขได้ด้วยตารางชั่วคราว
CREATE TABLE #RID (id int)
DECLARE @UID int =38
INSERT INTO #RID
SELECT r.id
from
Resources r where resourceUID = @UID
SELECT @uid, remark
from Settings s
INNER JOIN #RID r
ON r.id =s.resourceId
Order by typeID
OPTION(RECOMPILE)
DROP TABLE #RID
อีกครั้งกับความถูกต้องประมาณการ
สิ่งนี้ทำกับชุดข้อมูลของฉันเอง YMMV
เขียนด้วย sp_executesql
ด้วยตัวแปร
exec sp_executesql N'
DECLARE @RID int;
SELECT @RID=r.id from
Resources r where resourceUID = @UID;
SELECT @uid, remark
from Settings
where resourceId = @uid
Order by typeID
OPTION(RECOMPILE);',
N'@UID int',
@UID=38
ด้วยตารางชั่วคราว
exec sp_executesql N'
CREATE TABLE #RID (id int)
INSERT INTO #RID
SELECT r.id
from
Resources r where resourceUID = @UID
SELECT @uid, remark
from Settings s
INNER JOIN #RID r
ON r.id =s.resourceId
Order by typeID
OPTION(RECOMPILE)
DROP TABLE #RID',
N'@UID int',
@UID=38
ยังคงประมาณการที่ถูกต้อง 100% ในการทดสอบของฉัน
select r.id, LEFT(remark, 512)
(หรือความยาวซับสตริงที่สมเหตุสมผลก็ได้)