Database
 sql >> Baza danych >  >> RDS >> Database

Podejście do strojenia indeksów – część 2

W moim ostatnim poście zacząłem opisywać proces, przez który przechodzę podczas dostrajania zapytań – w szczególności, gdy odkrywam, że muszę dodać nowy indeks lub zmodyfikować istniejący. Do tego momentu zidentyfikowaliśmy problematyczne zapytanie, potrzebny mi indeks, jakie indeksy aktualnie istnieją w tabeli i czy te indeksy są używane. Gdy już mamy te dane, możemy przejść do kolejnych kroków w procesie.

Krok 5:Co używa indeksu

Oprócz sprawdzenia, jak często używany jest indeks (lub nie), warto wiedzieć, jakie zapytania użyj indeksu, szczególnie jeśli chcę połączyć go z innym indeksem. Na szczęście Jonathan Kehayias napisał już zapytanie, które pomoże określić, które plany korzystają z określonego indeksu. Jego wersja może być używana do pamięci podręcznej planu – jedynym wyzwaniem jest informacja, która jest przemijająca, więc możesz nie przechwycić każdego zapytania, które używa określonego indeksu. Query Store może w tym pomóc – zmodyfikowałem jego zapytanie, aby uzyskać te same informacje z planów w Query Store:

  SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
  DECLARE @IndexName AS NVARCHAR(128) = N'[IX_Sales_OrderLines_AllocatedStockItems]',
          @lb AS nchar(1) = N'[', @rb AS nchar(1) = N']';
 
  -- Make sure the name passed is appropriately quoted
  IF (LEFT(@IndexName, 1) <> @lb AND RIGHT(@IndexName, 1) <> @rb) SET @IndexName = QUOTENAME(@IndexName);
 
  --Handle the case where the left or right was quoted manually but not the opposite side
  IF LEFT(@IndexName, 1)  <> @lb SET @IndexName = @rb + @IndexName;
  IF RIGHT(@IndexName, 1) <> @rb SET @IndexName = @IndexName + @rb;
 
  ;WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')   
  SELECT
    stmt.value('(@StatementText)[1]', 'varchar(max)') AS SQL_Text,
    obj.value('(@Database)[1]', 'varchar(128)') AS DatabaseName,
    obj.value('(@Schema)[1]', 'varchar(128)') AS SchemaName,
    obj.value('(@Table)[1]', 'varchar(128)') AS TableName,
    obj.value('(@Index)[1]', 'varchar(128)') AS IndexName,
    obj.value('(@IndexKind)[1]', 'varchar(128)') AS IndexKind,
    query_plan
  FROM 	
  (
    SELECT query_plan
    FROM
    (
      SELECT TRY_CONVERT(XML, [qsp].[query_plan]) AS [query_plan]
      FROM sys.query_store_plan [qsp]
    ) tp
  ) AS tab (query_plan)
  CROSS APPLY query_plan.nodes('/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple') AS batch(stmt)
  CROSS APPLY stmt.nodes('.//IndexScan/Object[@Index=sql:variable("@IndexName")]') AS idx(obj)
  OPTION(MAXDOP 1, RECOMPILE);

Warto zauważyć, że jest to kolejny punkt, w którym mogę znaleźć się bardzo głęboko w króliczej norce, w zależności od liczby przeglądanych indeksów i liczby zapytań, które z nich korzystają. Jeśli to możliwe, rozważę również liczbę wykonań (ze sklepu zapytań lub pamięci podręcznej planu), aby nie tylko zrozumieć co zapytanie używa indeksu, ale jak często to zapytanie jest wykonywane. Tu strojenie indeksów staje się sztuką. Potrafię zebrać absurdalną ilość danych… ale nie mam nieskończonego czasu na analizę, więc muszę dokonać oceny, ile zapytań mam przejrzeć.

Krok 6:Testowanie

Najprościej rzecz ujmując, testowanie indeksu oznacza podjęcie problematycznego zapytania i przechwycenie planu i danych dotyczących wydajności (czas trwania, we/wy, procesor itp.), a następnie utworzenie indeksu, ponowne uruchomienie zapytania i przechwycenie tych samych informacji. Jeśli wydajność się poprawi, możesz jechać!

Rzadko jest to takie proste.

Na początek często mam co najmniej dwie odmiany indeksu, które chcę przetestować, czasem więcej. Zaczynam od linii bazowej, następnie tworzę wszystkie odmiany indeksu, czyszczę pamięć podręczną planu i sprawdzam, co wybierze SQL Server. Następnie przewijam i wymuszam każdy indeks wskazówką, przechwytując plan i metryki wydajności dla każdego wykonania. Uwaga:zakłada się, że mam wystarczająco dużo miejsca na dysku dla wszystkich indeksów… jeśli nie, to tworzę je pojedynczo i testuję. Na koniec porównuję liczby. Jeśli tylko dodaję nowy indeks, prawie skończę. Ale jeśli modyfikuję indeks lub łączę kilka ze sobą, może się to skomplikować.

W idealnym świecie, jeśli zmodyfikuję istniejący indeks, znajduję najczęstsze/ważniejsze zapytania korzystające z bieżącego indeksu i uzyskuję ich plany oraz metryki wydajności (jest to łatwe w przypadku Query Store). Następnie zmieniam indeks, ponownie uruchamiam wszystkie te zapytania i sprawdzam, czy uzyskuję znaczące zmiany w kształcie i/lub wydajności planu.

Jeśli scalę dwa indeksy, robię to samo, ale ze wszystkimi zapytaniami, które używają jednego z indeksów, a następnie ponownie testuję z scalonym indeksem.

Jeśli dodaję/zmieniam/łączę wiele indeksów dla tabeli, muszę pobrać wszystkie odpowiednie zapytania, ich plany i metryki, zmienić indeksy, a następnie ponownie uzyskać wszystkie informacje i porównać. Może to być bardzo czasochłonne, w zależności od liczby różnych zapytań. Tutaj jest to forma sztuki i musisz określić, ile zapytań naprawdę musisz przetestować. Jest to funkcja częstotliwości wykonywania, ważności/trafności zapytania oraz dostępnego/przydzielonego przeze mnie czasu.

Na koniec, jeśli dodam indeks do tabeli i nie usunę żadnych istniejących, to dodałem narzut dla INSERT, DELETE i potencjalnie UPDATE. Testowanie wydajności ta zmiana jest możliwa, ale potrzebujesz środowiska testowego i możliwości uruchomienia testu obciążenia oraz przechwytywania metryk przed i po zmianie związanych z czasem trwania, operacjami we/wy i procesorem.

To wielu przyjaciół, dlatego ironią jest, że początkowo pomyślałem o stwierdzeniu, że dostrajanie indeksu jest łatwe. Nie zawsze jest to proste, ale jest możliwe. To kwestia staranności i śledzenia tego wszystkiego.

Krok 7:Wdrożenie

Po sprawdzeniu nowych indeksów tak bardzo, jak to możliwe, jesteśmy gotowi do produkcji. Przyznaję, że zmiany indeksów postrzegam jako mało ryzykowne, szczególnie te nowe. Jeśli jest to problem, możesz go natychmiast usunąć i powrócić do pierwotnego stanu. W scenariuszu modyfikacji/scalania/upuszczania chcesz mieć wszystko ze skryptem, dzięki czemu możesz zmieniać i odtwarzać indeksy w razie potrzeby, aby zresetować indeksy. Zawsze zalecam początkowe wyłączenie indeksów zamiast ich upuszczania, ponieważ wtedy nie musisz się martwić o definicję – jeśli musisz ponownie dodać indeks, po prostu go przebuduj.

Podsumowanie

Twoja metoda dodawania i/lub konsolidacji indeksów może być inna! Podobnie jak dostrajanie zapytań, nie ma idealnego procesu. Miejmy nadzieję, że dla każdego, kto jest nowicjuszem w zakresie dostrajania indeksów, stanowi to początek elementów do przejrzenia i ważnych rozważań. Nie da się dodać indeksów bez dodawania pewnej ilości narzutu – i znowu w tym miejscu pojawia się sztuka:musisz określić, czy korzyści wynikające z indeksu przewyższają koszty modyfikacji.

Dostrajanie indeksu to ciągły, powtarzalny proces – nie sądzę, że kiedykolwiek skończyłeś, ponieważ zmienia się kod, dodawane są nowe tabele lub funkcje, a dane w tabelach się zmieniają. Kimberly ma dwa posty (https://www.sqlskills.com/blogs/kimberly/spring-cleaning-your-indexes-part-i/ i https://www.sqlskills.com/blogs/kimberly/spring-cleaning- your-indexes-part-ii/), które mówią o czyszczeniu indeksów — teraz jest najlepszy czas, aby zacząć! I wreszcie, gdy ktoś zapyta „ile indeksów powinno być dla tabeli?” Odpowiadam coś w stylu „najmniejsza liczba potrzebna do zaspokojenia jak największej liczby zapytań”. Nie ma magicznej liczby — widziałem tabele z zerowymi indeksami i widziałem tabele z ponad 100 (jestem pewien, że niektórzy z was widzieli wyższe liczby). Ani zero, ani 100 nie są dobre, ale „właściwa” liczba to taka, którą musisz ustalić, korzystając z dostępnych danych i swojego doświadczenia.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Dopasowanie podaży do popytu — rozwiązania, część 1

  2. Jak naprawić typowe błędy WordPress?

  3. Progi optymalizacji — grupowanie i agregowanie danych, część 5

  4. Praca z Salesforce.com w Alpha Anywhere

  5. Zapytania do bazy danych:jak znaleźć igłę w stogu siana?