Simpelt svar:NEJ. Du kan ikke hjælpe ad hoc-forespørgsler på en tabel med 238 kolonner med en 50 % Fill Factor på det Clustered Index.
Detaljeret svar:
Som jeg har sagt i andre svar om dette emne, er indeksdesign både kunst og videnskab, og der er så mange faktorer at overveje, at der er få, hvis nogen, hårde og hurtige regler. Du skal overveje:mængden af DML-operationer vs SELECT'er, diskundersystem, andre indekser / triggere på bordet, distribution af data i tabellen, er forespørgsler, der bruger SARGable WHERE-betingelser og flere andre ting, som jeg ikke engang kan huske rigtigt nu.
Jeg kan sige, at der ikke kan gives hjælp til spørgsmål om dette emne uden en forståelse af selve tabellen, dens indekser, triggere osv. Nu hvor du har postet tabeldefinitionen (venter stadig på indekserne, men tabeldefinitionen alene peger på 99 % af problemet) Jeg kan komme med nogle forslag.
For det første, hvis tabeldefinitionen er nøjagtig (238 kolonner, 50% Fill Factor), så kan du stort set ignorere resten af svarene/rådene her;-). Undskyld at være mindre-end-politisk her, men seriøst, det er en vild gåsejagt uden at kende detaljerne. Og nu, hvor vi ser tabeldefinitionen, bliver det en del klarere, hvorfor en simpel forespørgsel ville tage så lang tid, selv når testforespørgslerne (opdatering #1) kørte så hurtigt.
Hovedproblemet her (og i mange situationer med dårlig ydeevne) er dårlig datamodellering. 238 kolonner er ikke forbudt ligesom at have 999 indekser ikke er forbudt, men det er generelt heller ikke særlig klogt.
Anbefalinger:
- For det første skal denne tabel virkelig ombygges. Hvis dette er en data warehouse tabel så måske, men hvis ikke så skal disse felter virkelig brydes op i flere tabeller som alle kan have den samme PK. Du ville have en master record-tabel, og de underordnede tabeller er kun afhængige oplysninger baseret på almindeligt associerede attributter, og PK'en for disse tabeller er den samme som PK'en for mastertabellen og dermed også FK til mastertabellen. Der vil være et 1-til-1 forhold mellem master og alle underordnede tabeller.
- Brugen af
ANSI_PADDING OFF
er foruroligende, for ikke at sige inkonsistent i tabellen på grund af de forskellige kolonnetilføjelser over tid. Ikke sikker på, om du kan rette det nu, men ideelt set ville du altid haveANSI_PADDING TIL
, eller i det mindste have den samme indstilling på tværs af alleALTER TABLE
udsagn. - Overvej at oprette 2 yderligere filgrupper:Tabeller og indekser. Det er bedst ikke at lægge dine ting i
PRIMARY
da det er her SQL SERVER gemmer alle sine data og metadata om dine objekter. Du opretter din tabel og klyngede indeks (da det er dataene for tabellen) på[Tables]
og alle ikke-klyngede indekser på[Indekser]
- Forøg fyldningsfaktoren fra 50 %. Dette lave tal er sandsynligvis grunden til, at dit indeksrum er større end dit datarum. Hvis du laver en indeksgenopbygning, genskabes datasiderne med et maksimum på 4k (ud af den samlede sidestørrelse på 8k), der bruges til dine data, så din tabel er spredt ud over et bredt område.
- Hvis de fleste eller alle forespørgsler har "ER101_ORG_CODE" i
WHERE
betingelse, så overvej at flytte det til den forreste kolonne i det klyngede indeks. Forudsat at det bruges oftere end "ER101_ORD_NBR". Hvis "ER101_ORD_NBR" bruges oftere, så behold det. Det ser bare ud til, hvis det antages, at feltnavnene betyder "OrganizationCode" og "OrderNumber", at "OrgCode" er en bedre gruppering, der kan have flere "OrderNumbers" i sig. - Mindre punkt, men hvis "ER101_ORG_CODE" altid er på 2 tegn, så brug
CHAR(2)
i stedet forVARCHAR(2)
da det vil gemme en byte i rækkeoverskriften, som sporer variable breddestørrelser og tæller over millioner af rækker. - Som andre her har nævnt, brug
SELECT *
vil skade præstationen. Ikke kun fordi det kræver, at SQL Server returnerer alle kolonner og dermed er mere tilbøjelige til at lave en Clustered Index Scan uanset dine andre indekser, men det tager også SQL Server tid at gå til tabeldefinitionen og oversætte* ind i alle kolonnenavnene. Det skal være lidt hurtigere at angive alle 238 kolonnenavne i
SELECT
listen, selvom det ikke hjælper scanningsproblemet. Men har du nogensinde virkelig brug for alle 238 kolonner på samme tid alligevel?
Held og lykke!
OPDATERING
For fuldstændighedens skyld til spørgsmålet "hvordan man forbedrer ydeevnen på en stor tabel til ad hoc-forespørgsler", skal det bemærkes, at selvom det ikke hjælper i dette specifikke tilfælde, HVIS nogen bruger SQL Server 2012 (eller nyere, når den tid kommer), og HVIS tabellen ikke bliver opdateret, så er det en mulighed at bruge Columnstore Indexes. For flere detaljer om den nye funktion, se her:http://msdn.microsoft.com/en-us/library/gg492088.aspx (jeg tror, at disse blev lavet til at kunne opdateres fra og med SQL Server 2014).
OPDATERING 2
Yderligere overvejelser er:
- Aktiver komprimering på Clustered Index. Denne mulighed blev tilgængelig i SQL Server 2008, men kun som en Enterprise Edition-funktion. Men fra SQL Server 2016 SP1 , Datakomprimering blev gjort tilgængelig i alle udgaver! Se venligst MSDN-siden for datakomprimering for detaljer om række- og sidekomprimering.
- Hvis du ikke kan bruge datakomprimering, eller hvis det ikke giver den store fordel for en bestemt tabel, så HVIS du har en kolonne af en type med fast længde (
INT
,BIGINT
,TINYINT
,SMALLINT
,CHAR
,NCHAR
,BINÆR
,DATETIME
,SMALLDATETIME
,PENGE
, etc) og godt 50 % af rækkerne erNULL
, og overvej derefter at aktivereSPARSE
mulighed, som blev tilgængelig i SQL Server 2008. Se venligst MSDN-siden for Brug sparse kolonner for detaljer.