Đối với tôi, có vẻ như where
mệnh đề trong truy vấn đang đưa ra vấn đề và là nguyên nhân của các ước tính thấp, ngay cả khi OPTION(RECOMPILE)
được sử dụng.
Tôi đã tạo một số dữ liệu thử nghiệm và cuối cùng đã đưa ra hai giải pháp, lưu trữ ID
trường từ resources
một biến (nếu nó luôn là duy nhất) hoặc bảng tạm thời, nếu chúng ta có thể có nhiều hơn một ID
.
Hồ sơ kiểm tra cơ sở
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
Chèn các giá trị 'Tìm kiếm', để có được kết quả gần đúng tương tự như OP (1300 bản ghi)
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
Thay đổi số liệu thống kê và cập nhật để phù hợp với OP
ALTER DATABASE StackOverflow SET COMPATIBILITY_LEVEL = 120;
UPDATE STATISTICS settings WITH FULLSCAN;
UPDATE STATISTICS resources WITH FULLSCAN;
Truy vấn gốc
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
Ước tính của tôi thậm chí còn tồi tệ hơn , với một hàng ước tính, trong khi 1300 được trả lại. Và như OP đã nêu, không có vấn đề gì nếu tôi thêmOPTION(RECOMPILE)
Một điều quan trọng cần lưu ý là khi chúng ta thoát khỏi mệnh đề where, các ước tính là chính xác 100%, điều này được mong đợi vì chúng ta đang sử dụng tất cả dữ liệu trong cả hai bảng.
Tôi đã buộc các chỉ mục chỉ để đảm bảo rằng chúng tôi sử dụng các chỉ mục giống như trong truy vấn trước đó, để chứng minh luận điểm
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
Như mong đợi, ước tính tốt .
Vì vậy, những gì chúng ta có thể thay đổi để có được ước tính tốt hơn nhưng vẫn tìm kiếm các giá trị của chúng tôi?
NẾU @UID là duy nhất, như trong ví dụ OP đã đưa ra, chúng ta có thể đặt đơn id
được trả về từ resources
một biến, sau đó tìm kiếm biến đó bằng TÙY CHỌN (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);
Ước tính chính xác 100%.
Nhưng nếu có nhiều tài nguyênUID trong tài nguyên thì sao?
thêm một số dữ liệu thử nghiệm
INSERT INTO Resources(ResourceUID)
VALUES (38);
go 50
Điều này có thể được giải quyết với một bảng tạm thời
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
Một lần nữa với ước tính chính xác .
Điều này đã được thực hiện với bộ dữ liệu của riêng tôi, YMMV.
Được viết bằng sp_executesql
Với một biến
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
Với một bảng tạm thời
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
Vẫn đúng 100% ước tính trong bài kiểm tra của tôi
select r.id, LEFT(remark, 512)
(hoặc bất kỳ chiều dài chuỗi con hợp lý nào có thể).