Jak zapobiec tworzeniu statystyk w kolumnie?

18

Mam tabelę z kolumną, w której nie chcę, aby statystyki były tworzone lub aktualizowane. Lepsze oszacowanie liczności złączeń uzyskuję, jeśli wymuszę na narzędziu optymalizującym kwerendy użycie gęstości statystyki na kluczu podstawowym, a nie histogramu statystyki w tej kolumnie. Automatyczne aktualizowanie i automatyczne tworzenie statystyk są włączone na poziomie bazy danych i nie mogę tego zmienić.

Jeśli chcesz zasugerować alternatywy dla zapobiegania tworzeniu statystyk, pamiętaj, że tabela jest używana w widoku, do którego odwołują się tysiące różnych zapytań. Nie mam kontroli nad uruchomionymi zapytaniami.

Moja początkowa strategia polegała na tworzeniu statystyk w kolumnie z opcjami NOCOMPUTEi SAMPLE 0 ROWS. Miałem wrażenie, że SQL Server nie utworzy automatycznie statystyk w kolumnie, która ma już obiekt statystyki, ale stało się tak na naszych serwerach deweloperów i QA.

Nowe statystyki zostały utworzone dla COL_GROUP. Moja NORECOMPUTEstatystyka nie została zaktualizowana. Nie wiem, dlaczego statystyki zostały utworzone i sam nie byłem w stanie wyzwolić tego, uruchamiając zapytania.

Czy istnieje sposób, aby uniemożliwić programowi SQL Server automatyczne tworzenie statystyk w jednej kolumnie? Moja tabela ma tylko dwie kolumny, więc rozwiązanie, które zapobiega tworzeniu automatycznych statystyk w jednej tabeli, również rozwiązałoby mój problem.

Flagi śledzenia 4139 i 2371 są włączone na wypadek, gdyby miało to znaczenie.

Jeśli chcesz się pobawić strukturą tabeli, zamieściłem ją i przykładowe dane poniżej:

CREATE TABLE X_NO_COLUMN_STATS(
    [COL_USER] [varchar](256) NOT NULL,
    [COL_GROUP] [int] NOT NULL,
 CONSTRAINT [PK_X_NO_COLUMN_STATS] PRIMARY KEY CLUSTERED 
(
    [COL_USER] ASC,
    [COL_GROUP] ASC
)WITH (DATA_COMPRESSION = PAGE)
);

-- prevent stats from being updated on COL_GROUP
CREATE STATISTICS [X_NO_COLUMN_STATS__COL_GROUP] ON X_NO_COLUMN_STATS ([COL_GROUP]) WITH NORECOMPUTE, SAMPLE 0 ROWS;

BEGIN TRANSACTION;
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',104);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',106);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',107);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',108);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',110);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',111);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',112);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',113);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',114);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',116);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',117);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',118);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',121);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',123);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',124);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',125);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',126);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',129);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',132);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',137);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',139);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',140);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',144);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',145);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',147);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',152);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',153);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',154);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',155);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',162);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',163);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',165);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',168);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',169);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',170);
INSERT INTO X_NO_COLUMN_STATS VALUES ('CUSER1',178);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',102);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',103);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',109);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',110);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',111);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',112);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',114);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',115);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',119);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',120);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',121);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',123);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',124);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',126);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',128);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',136);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',137);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',138);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',142);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',143);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',148);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',151);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',152);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',155);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',156);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',157);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',158);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',165);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',167);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',168);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',169);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',171);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',173);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',176);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',177);
INSERT INTO X_NO_COLUMN_STATS VALUES ('OUSER19',178);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',104);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',108);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',109);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',111);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',112);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',113);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',114);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',116);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',117);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',118);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',121);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',123);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',124);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',125);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',126);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',129);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',132);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',137);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',139);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',140);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',144);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',145);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',147);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',152);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',154);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',155);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',162);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',163);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',165);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',168);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',169);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',170);
INSERT INTO X_NO_COLUMN_STATS VALUES ('TUSER30',178);
COMMIT TRANSACTION;

Wiem o tym, sp_autostatsale potrzebuję czegoś, co uniemożliwi tworzenie automatycznych statystyk. sp_autostatszapobiega tylko automatycznej aktualizacji statystyk.

Joe Obbish
źródło
1
Ile danych zawiera Twoja aktualna tabela? A ile danych dodaje się codziennie?
John aka hot2use,
Czy zastanawiałeś się nad stworzeniem statystyki dla obu kolumn i zobaczyłeś, jak wpływa to na wydajność zapytania? UTWÓRZ STATYSTYKI [X_NO_COLUMN_STATS__COL_GROUP] NA X_NO_COLUMN_STATS ([COL_USER], [COL_GROUP]); Jeśli obie kolumny znajdują się w klauzuli where, nie utworzy statystyki na COL_GROUP, ale jeśli tylko COL_GROUP, to zrobi to. Ale w takim przypadku wydajność powinna być lepsza z tą statystyką niż statystyka COL_USER.
cfradenburg

Odpowiedzi:

1

Utwórz nową bazę danych (nazwijmy ją TestStats), wyłącz opcję automatycznego tworzenia statystyk i przenieś tam tabelę X_NO_COLUMN_STATS. Następnie utwórz widok w bazie danych, który będzie wskazywał na tabelę bez histogramu:

CREATE VIEW X_NO_COLUMN_STATS
AS
    SELECT [COL_USER], [COL_GROUP] FROM TestStats.dbo.X_NO_COLUMN_STATS;
GO

Jeśli w tym momencie poprawnie zrozumiem twój problem, osiągniesz to, co chcesz. Twoje operacje CRUD będą działać z tabelą bez statystyk (tak, będzie ona umieszczona w innej bazie danych, o czym należy zawsze pamiętać) poprzez widok o tej samej nazwie co twoja tabela.

Denis Reznik
źródło
Niestety ma to wiele wad: zrywa relacje między kluczami obcymi, wprowadza transakcje między bazami danych, sprawia, że ​​tworzenie kopii zapasowych i odzyskiwanie danych w jednym miejscu jest o wiele trudniejsze itp.
Brent Ozar,
@BrentOzar na pewno! Ale zdarza się to dość często w przypadku trudnych zadań - decydowanie, co będzie tutaj gorsze :)
Denis Reznik