Мне кажется, что 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 возвращаются. И, как указано в ОП, не имеет значения, если я добавлюOPTION(RECOMPILE)
Важно отметить, что когда мы избавляемся от предложения where, оценки оказываются на 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
Как и следовало ожидать, хорошие оценки.
Итак, что мы можем изменить, чтобы получить более точные оценки, но при этом стремиться к нашим ценностям?
Если @UID уникален, как в примере, приведенном OP, мы можем поместить сингл 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)
(или любой разумной длины подстроки может быть).