Як уже зазначалося в коментарях, схоже, вам потрібно оновити статистику.
Орієнтовна кількість рядків, що виходять із з'єднання між ними, location
і testruns
сильно відрізняється між двома планами.
Приєднайтесь до кошторису плану: 1
Оцінка плану підзапиту: 8,748
Фактична кількість рядків, що виходять із з'єднання, становить 14 276.
Звичайно, абсолютно не має ніякого інтуїтивного сенсу, що версія приєднання повинна оцінювати, що 3 рядки повинні надходити з location
одного рядка, що з'єднався, тоді як підзапит запитує, що один із цих рядків отримає 8 748 з того самого з'єднання, але, тим не менш, я зміг щоб відтворити це.
Це, мабуть, трапиться, якщо між гістограмами немає перехрестя при створенні статистики. Версія приєднання передбачає один рядок. І одноосібний пошук рівності підзапиту передбачає ті ж оцінені рядки, що й пошук рівності проти невідомої змінної.
Кардинальність теструнів є 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' )