Mam taki stół:
CREATE TABLE Updates
(
UpdateId INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
ObjectId INT NOT NULL
)
Zasadniczo śledzenie aktualizacji obiektów o rosnącym ID.
Konsument tej tabeli wybiera fragment 100 różnych identyfikatorów obiektów, uporządkowanych według UpdateId
i rozpoczynając od określonego UpdateId
. Zasadniczo, śledząc, gdzie przerwał, a następnie sprawdzając wszelkie aktualizacje.
Uważam, że jest to interesujący problem z optymalizacją, ponieważ byłem w stanie wygenerować maksymalnie optymalny plan zapytań, pisząc zapytania, które akurat robią to, co chcę z powodu indeksów, ale nie gwarantuję tego, czego chcę:
SELECT DISTINCT TOP 100 ObjectId
FROM Updates
WHERE UpdateId > @fromUpdateId
Gdzie @fromUpdateId
jest parametr procedury składowanej.
Z planem:
SELECT <- TOP <- Hash match (flow distinct, 100 rows touched) <- Index seek
Z powodu wykorzystywanego wyszukiwania UpdateId
indeksu wyniki są już ładne i uporządkowane od najniższego do najwyższego identyfikatora aktualizacji, tak jak chcę. I to generuje odrębny plan przepływu , czego chcę. Ale porządkowanie oczywiście nie jest gwarantowanym zachowaniem, więc nie chcę go używać.
Ta sztuczka daje również ten sam plan zapytań (choć ze zbędnym TOP):
WITH ids AS
(
SELECT ObjectId
FROM Updates
WHERE UpdateId > @fromUpdateId
ORDER BY UpdateId OFFSET 0 ROWS
)
SELECT DISTINCT TOP 100 ObjectId FROM ids
Chociaż nie jestem pewien (i nie podejrzewam), czy to naprawdę gwarantuje zamówienie.
Jedno z zapytań, które miałem nadzieję, że SQL Server będzie wystarczająco inteligentny, aby uprościć to, ale w końcu generuje bardzo zły plan zapytań:
SELECT TOP 100 ObjectId
FROM Updates
WHERE UpdateId > @fromUpdateId
GROUP BY ObjectId
ORDER BY MIN(UpdateId)
Z planem:
SELECT <- Top N Sort <- Hash Match aggregate (50,000+ rows touched) <- Index Seek
Próbuję znaleźć sposób na wygenerowanie optymalnego planu z wyszukiwaniem indeksu UpdateId
i przepływem odrębnym do usuwania duplikatów ObjectId
. Jakieś pomysły?
Przykładowe dane, jeśli chcesz. Obiekty rzadko będą miały więcej niż jedną aktualizację i prawie nigdy nie powinny mieć więcej niż jednej aktualizacji w zestawie 100 wierszy, dlatego właśnie mam wyraźny przepływ , chyba że jest coś lepszego, o czym nie wiem? Jednak nie ma gwarancji, że jeden ObjectId
nie będzie miał więcej niż 100 wierszy w tabeli. Tabela ma ponad 1 000 000 wierszy i oczekuje się szybkiego wzrostu.
Załóżmy, że użytkownik tego ma inny sposób na znalezienie odpowiedniego następnego @fromUpdateId
. Nie ma potrzeby zwracania go w tym zapytaniu.
źródło