sql >> Databasteknik >  >> RDS >> Sqlserver

Förbättra SQL Server-frågeprestanda på stora tabeller

Enkelt svar:NEJ. Du kan inte hjälpa ad hoc-frågor på en tabell med 238 kolumner med en fyllningsfaktor på 50 % på det klustrade indexet.

Detaljerat svar:

Som jag har sagt i andra svar om detta ämne, är Indexdesign både konst och vetenskap och det finns så många faktorer att ta hänsyn till att det finns få, om några, hårda och snabba regler. Du måste tänka på:volymen av DML-operationer vs SELECT, diskundersystem, andra index / triggers på tabellen, distribution av data i tabellen, är frågor som använder SARGable WHERE-villkor och flera andra saker som jag inte ens kommer ihåg rätt. nu.

Jag kan säga att ingen hjälp kan ges för frågor om detta ämne utan en förståelse av själva tabellen, dess index, triggers, etc. Nu när du har lagt upp tabelldefinitionen (väntar fortfarande på indexen men bara tabelldefinitionen pekar på 99 % av problemet) Jag kan ge några förslag.

För det första, om tabelldefinitionen är korrekt (238 kolumner, 50 % fyllningsfaktor) så kan du i stort sett ignorera resten av svaren/råden här;-). Ledsen att jag är mindre-än-politisk här, men allvarligt talat, det är en vild gåsjakt utan att känna till detaljerna. Och nu när vi ser tabelldefinitionen blir det ganska lite tydligare varför en enkel fråga skulle ta så lång tid, även när testfrågorna (uppdatering #1) gick så snabbt.

Det största problemet här (och i många situationer med dålig prestanda) är dålig datamodellering. 238 kolumner är inte förbjudna precis som att ha 999 index inte är förbjudet, men det är i allmänhet inte särskilt klokt.

Rekommendationer:

  1. För det första behöver den här tabellen verkligen göras om. Om detta är en datalagertabell så kanske, men om inte så måste dessa fält verkligen delas upp i flera tabeller som alla kan ha samma PK. Du skulle ha en masterposttabell och de underordnade tabellerna är bara beroende av information baserad på vanliga attribut och PK för dessa tabeller är samma som PK för mastertabellen och därmed också FK till mastertabellen. Det kommer att finnas en 1-till-1-relation mellan master och alla underordnade tabeller.
  2. Användningen av ANSI_PADDING OFF är störande, för att inte säga inkonsekvent i tabellen på grund av de olika kolumntilläggen över tiden. Inte säker på om du kan fixa det nu, men helst skulle du alltid ha ANSI_PADDING PÅ , eller åtminstone ha samma inställning över alla ALTER TABLE uttalanden.
  3. Överväg att skapa ytterligare två filgrupper:tabeller och index. Det är bäst att inte lägga dina saker i PRIMÄR eftersom det är där SQL SERVER lagrar all sin data och metadata om dina objekt. Du skapar din tabell och klustrade index (eftersom det är data för tabellen) på [Tables] och alla icke-klustrade index på [Index]
  4. Öka fyllningsfaktorn från 50 %. Detta låga antal är troligen varför ditt indexutrymme är större än ditt datautrymme. Om du gör en ombyggnad av indexet kommer datasidorna att återskapas med max 4k (av den totala sidstorleken på 8k) som används för dina data så att din tabell sprids över ett stort område.
  5. Om de flesta eller alla frågor har "ER101_ORG_CODE" i WHERE villkor, överväg sedan att flytta det till den inledande kolumnen i det klustrade indexet. Förutsatt att den används oftare än "ER101_ORD_NBR". Om "ER101_ORD_NBR" används oftare, behåll den. Det verkar bara, om man antar att fältnamnen betyder "OrganizationCode" och "OrderNumber", som "OrgCode" är en bättre gruppering som kan ha flera "OrderNumbers" inom sig.
  6. Mindre poäng, men om "ER101_ORG_CODE" alltid är 2 tecken, använd CHAR(2) istället för VARCHAR(2) eftersom det kommer att spara en byte i radhuvudet som spårar varierande breddstorlekar och summerar över miljontals rader.
  7. Som andra här har nämnt, använd SELECT * kommer att skada prestandan. Inte bara på grund av att det kräver att SQL Server returnerar alla kolumner och därmed är mer benägna att göra en Clustered Index Scan oavsett dina andra index, utan det tar också SQL Server tid att gå till tabelldefinitionen och översätta * i alla kolumnnamn. Det borde vara lite snabbare att ange alla 238 kolumnnamn i SELECT listan men det hjälper inte skanningsproblemet. Men behöver du verkligen alla 238 kolumner samtidigt?

Lycka till!

UPPDATERA
För fullständighetens skull till frågan "hur man förbättrar prestanda på en stor tabell för ad-hoc-frågor", bör det noteras att även om det inte hjälper för det här specifika fallet, OM någon använder SQL Server 2012 (eller nyare när den tiden kommer) och OM tabellen inte uppdateras är det ett alternativ att använda Columnstore Index. För mer information om den nya funktionen, titta här:http://msdn.microsoft.com/en-us/library/gg492088.aspx (jag tror att dessa gjordes för att kunna uppdateras från och med SQL Server 2014).

UPPDATERING 2
Ytterligare överväganden är:

  • Aktivera komprimering på Clustered Index. Det här alternativet blev tillgängligt i SQL Server 2008, men endast som en Enterprise Edition-funktion. Men från och med SQL Server 2016 SP1 , Datakompression gjordes tillgänglig i alla utgåvor! Se MSDN-sidan för datakomprimering för detaljer om rad- och sidkomprimering.
  • Om du inte kan använda datakomprimering, eller om det inte ger någon större fördel för en viss tabell, så OM du har en kolumn av en typ av fast längd (INT , STORT , TINYINT , SMALLINT , CHAR , NCHAR , BINÄR , DATETIME , SMALLDATETIME , PENGAR , etc) och långt över 50 % av raderna är NULL , överväg sedan att aktivera SPARSE alternativ som blev tillgängligt i SQL Server 2008. Se MSDN-sidan för Använd glesa kolumner för detaljer.


  1. Hur man kontrollerar om en tabell finns i SQLite

  2. Hur använder man en paketkonstant i SQL SELECT-satsen?

  3. Hitta det refererade tabellnamnet med hjälp av tabell-, fält- och schemanamn

  4. LEN() vs DATALENGTH() i SQL Server