Prosta odpowiedź:NIE. Nie można pomóc kwerendom ad hoc w tabeli 238 kolumn z 50% współczynnikiem wypełnienia indeksu klastrowego.
Szczegółowa odpowiedź:
Jak już wspomniałem w innych odpowiedziach na ten temat, projektowanie indeksów jest zarówno sztuką, jak i nauką i jest tak wiele czynników, które należy wziąć pod uwagę, że istnieje niewiele, jeśli w ogóle, twardych i szybkich zasad. Trzeba wziąć pod uwagę:wielkość operacji DML vs SELECTy, podsystem dyskowy, inne indeksy/triggery w tabeli, dystrybucja danych w tabeli, to zapytania używające warunków SARGable WHERE i kilka innych rzeczy, których nawet nie pamiętam dobrze teraz.
Mogę powiedzieć, że nie można udzielić pomocy w przypadku pytań na ten temat bez zrozumienia samej tabeli, jej indeksów, wyzwalaczy itp. Teraz, gdy opublikowałeś definicję tabeli (wciąż czekasz na indeksy, ale sama definicja tabeli wskazuje na 99% problemu) Mogę zaoferować kilka sugestii.
Po pierwsze, jeśli definicja tabeli jest dokładna (238 kolumn, 50% współczynnik wypełnienia), możesz zignorować resztę odpowiedzi / porad tutaj;-). Przepraszam, że jestem mniej niż polityczny tutaj, ale poważnie, to szalona pogoń za dzikimi gęsiami bez znajomości szczegółów. A teraz, gdy widzimy definicję tabeli, staje się nieco jaśniejsze, dlaczego proste zapytanie zajęłoby tak długo, nawet jeśli zapytania testowe (aktualizacja nr 1) przebiegały tak szybko.
Głównym problemem tutaj (i w wielu sytuacjach o niskiej wydajności) jest złe modelowanie danych. 238 kolumn nie jest zabronione, podobnie jak posiadanie 999 indeksów nie jest zabronione, ale generalnie nie jest to zbyt mądre.
Zalecenia:
- Po pierwsze, ten stół naprawdę wymaga przebudowy. Jeśli jest to tabela hurtowni danych, to może, ale jeśli nie, to te pola naprawdę muszą zostać podzielone na kilka tabel, z których każda może mieć tę samą PK. Miałbyś główną tabelę rekordów, a tabele podrzędne są tylko informacjami zależnymi opartymi na powszechnie powiązanych atrybutach, a PK tych tabel jest takie samo jak PK tabeli głównej, a zatem również FK do tabeli głównej. Będzie relacja 1 do 1 między tabelami głównymi i wszystkimi tabelami podrzędnymi.
- Korzystanie z
ANSI_PADDING OFF
jest niepokojące, nie wspominając o niespójności w tabeli ze względu na różne dodawanie kolumn w czasie. Nie jestem pewien, czy możesz to teraz naprawić, ale najlepiej zawsze miećANSI_PADDING ON
, lub przynajmniej mieć to samo ustawienie we wszystkichALTER TABLE
oświadczenia. - Rozważ utworzenie 2 dodatkowych grup plików:tabel i indeksów. Najlepiej nie umieszczać swoich rzeczy w
PRIMARY
ponieważ to tam SQL SERVER przechowuje wszystkie swoje dane i metadane dotyczące twoich obiektów. Tworzysz tabelę i indeks klastrowy (jako że są to dane dla tabeli) na[Tables]
i wszystkie indeksy nieklastrowe na[Indeksy]
- Zwiększ współczynnik wypełnienia z 50%. Ta niska liczba jest prawdopodobnie powodem, dla którego przestrzeń indeksu jest większa niż przestrzeń danych. Wykonanie przebudowy indeksu spowoduje odtworzenie stron danych z maksymalnym rozmiarem 4k (z całkowitego rozmiaru strony 8k) używanych dla danych, dzięki czemu tabela jest rozłożona na dużym obszarze.
- Jeśli większość lub wszystkie zapytania mają „ER101_ORG_CODE” w
WHERE
warunek, a następnie rozważ przeniesienie go do wiodącej kolumny indeksu klastrowego. Zakładając, że jest używany częściej niż „ER101_ORD_NBR”. Jeśli „ER101_ORD_NBR” jest używane częściej, zachowaj je. Po prostu wydaje się, zakładając, że nazwy pól oznaczają „OrganizationCode” i „OrderNumber”, że „OrgCode” jest lepszą grupą, która może zawierać wiele „OrderNumbers”. - Mniejszy punkt, ale jeśli „ER101_ORG_CODE” ma zawsze 2 znaki, użyj
CHAR(2)
zamiastVARCHAR(2)
ponieważ zapisze bajt w nagłówku wiersza, który śledzi rozmiary o zmiennej szerokości i dodaje ponad miliony wierszy. - Jak wspomnieli inni, używając
SELECT *
zaszkodzi wydajności. Nie tylko ze względu na to, że SQL Server wymaga zwrócenia wszystkich kolumn, a tym samym zwiększa prawdopodobieństwo wykonania klastrowego skanowania indeksu niezależnie od innych indeksów, ale także przejście do definicji tabeli i przetłumaczenie* do wszystkich nazw kolumn. Powinno być nieco szybciej określić wszystkie 238 nazw kolumn w
SELECT
Lista jednak nie pomoże w problemie ze skanowaniem. Ale czy naprawdę potrzebujesz wszystkich 238 kolumn jednocześnie?
Powodzenia!
AKTUALIZUJ
Dla kompletności pytania "jak poprawić wydajność na dużej tabeli dla zapytań ad-hoc", należy zauważyć, że chociaż nie pomoże w tym konkretnym przypadku, JEŚLI ktoś używa SQL Server 2012 (lub nowsze, gdy nadejdzie ten czas) i JEŚLI tabela nie jest aktualizowana, to użycie indeksów magazynu kolumn jest opcją. Aby uzyskać więcej informacji na temat tej nowej funkcji, zajrzyj tutaj:http://msdn.microsoft.com/en-us/library/gg492088.aspx (wierzę, że zostały one stworzone, aby można je było aktualizować od SQL Server 2014).
AKTUALIZACJA 2
Dodatkowe uwagi to:
- Włącz kompresję w indeksie klastrowym. Ta opcja stała się dostępna w programie SQL Server 2008, ale jako funkcja dostępna tylko w wersji Enterprise Edition. Jednak od SQL Server 2016 SP1 , Kompresja danych została udostępniona we wszystkich edycjach! Zobacz stronę MSDN dotyczącą kompresji danych, aby uzyskać szczegółowe informacje na temat kompresji wierszy i stron.
- Jeśli nie możesz użyć kompresji danych lub jeśli nie przyniesie to większych korzyści dla określonej tabeli, to JEŚLI masz kolumnę typu o stałej długości (
INT
,BIGINT
,TINYINT
,MAŁE
,ZNAK
,NCHAR
,BINARNY
,DATETIME
,SMALLDATETIME
,PIENIĄDZE
, itp) i znacznie ponad 50% wierszy ma wartośćNULL
, a następnie rozważ włączenie opcjiSPARSE
opcja, która stała się dostępna w SQL Server 2008. Aby uzyskać szczegółowe informacje, zobacz stronę MSDN, aby uzyskać informacje na temat używania rzadkich kolumn.