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

Magazyn zapytań:pokazywanie wpływu indeksów na wstawki

Wprowadzenie

W kręgach baz danych powszechnie wiadomo, że indeksy poprawiają wydajność zapytań albo całkowicie spełniają wymagany zestaw wyników (Covering Indexes) lub działają jako wyszukiwania, które z łatwością kierują silnik zapytań do dokładnej lokalizacji wymaganego zestawu danych. Jednak, jak wiedzą doświadczeni administratorzy baz danych, nie należy być entuzjastycznie nastawionym do tworzenia indeksów w środowiskach OLTP bez zrozumienia natury obciążenia. Używając Query Store w instancji SQL Server 2019 (Query Store został wprowadzony w SQL Server 2016), dość łatwo jest pokazać wpływ indeksu na wstawki.

Wstaw bez indeksu

Zaczynamy od przywrócenia bazy danych WideWorldImporters Sample, a następnie utworzenia kopii Sales. Tabela faktur przy użyciu skryptu z Listingu 1. Zauważ, że przykładowa baza danych ma już włączoną opcję Query Store w trybie do odczytu i zapisu.

-- Listing 1 Utwórz kopię fakturSELECT * INTO [SPRZEDAŻ].[INVOICES1] FROM [SPRZEDAŻ].[INVOICES] WHERE 1=2;

Zauważ, że w tabeli, którą właśnie utworzyliśmy, nie ma żadnych indeksów. Wszystko, co mamy, to struktura tabeli. Po zakończeniu wstawiamy do nowej tabeli, używając danych z jej rodzica, jak pokazano na Listingu 2.

-- Listing 2 Wypełnij Faktury1-- OBCIĄĆ TABELĘ [SPRZEDAŻ].[FAKTURY1]WSTAW DO [SPRZEDAŻ].[FAKTURY1] SELECT * Z [SPRZEDAŻ].[FAKTURY]; PRZEJDŹ 100

Podczas tej operacji Query Store przechwytuje plan wykonania zapytania. Rysunek 1 pokazuje pokrótce, co dzieje się pod maską. Czytając od lewej do prawej, widzimy, że SQL Server wykonuje wstawki przy użyciu Identyfikatora planu 563 – skanowanie indeksu klucza podstawowego tabeli źródłowej w celu pobrania danych, a następnie wstawienie tabeli do tabeli docelowej. (Czytanie od lewej do prawej). Zauważ, że w tym przypadku większość kosztów znajduje się na wstawce do tabeli – 99% kosztu zapytania.

Rys. 1 Plan wykonania 563

Rys. 2 Wstawianie tabeli w miejscu docelowym

Rys. 3 Skanowanie indeksu klastrowego w tabeli źródłowej

Wstaw z indeksem

Następnie tworzymy indeks w tabeli docelowej za pomocą DDL z Listingu 3. Kiedy powtarzamy instrukcję z Listingu 2 po obcięciu tabeli docelowej, widzimy nieco inny plan wykonania (Plan ID 593 pokazany na Rys. 4). Nadal widzimy wstawkę tabeli, ale przyczynia się ona tylko do 58% do kosztu zapytania. Dynamika wykonania jest nieco wypaczona przez wprowadzenie sortowania i wkładki indeksowej. Zasadniczo dzieje się tak, że SQL Server musi wprowadzać odpowiednie wiersze do indeksu, gdy nowe rekordy są wprowadzane do tabeli.

-- LISTA 3 Utwórz indeks w tabeli docelowej UTWÓRZ INDEKS NIESKLUSTROWANY [IX_Sales_Invoices_ConfirmedDeliveryTime] ON [Sales].[Invoices1]([ConfirmedDeliveryTime] ASC)INCLUDE ([ConfirmedReceivedBy]) WITH (PAD_INDUTEICS_OFF_MPRTICS_ OFF, ECORTICS =OFF, ECORT , DROP_EXISTING =WYŁĄCZONE, ONLINE =WYŁĄCZONE, ALLOW_ROW_LOCKS =WŁĄCZONE, ALLOW_PAGE_LOCKS =WŁĄCZONE) WŁĄCZONE [USERDATA]GO

Rys. 4 Plan wykonania 593

Patrząc głębiej

Możemy zbadać szczegóły obu planów i zobaczyć, jak te nowe czynniki eskalują czas wykonania zestawienia. Plan 593 dodaje dodatkowe 300 ms do średniego czasu trwania wyciągu. Przy dużym obciążeniu pracą w środowisku produkcyjnym ta różnica może być znacząca.

Włączenie operacji we/wy STATISTICS podczas wykonywania instrukcji INSERT tylko raz w obu przypadkach — z indeksem w tabeli docelowej i bez indeksu w tabeli docelowej — pokazuje również, że więcej pracy jest wykonywane w zakresie logicznego we/wy podczas wstawiania wierszy w tabeli z indeksami.

Rys. 5 Szczegóły planu wykonania 563

Rys. 4 Szczegóły planu wykonania 593

Brak indeksu:dane wyjściowe z włączoną funkcją STATISTICS IO:

Tabela „Faktury1”. Liczba skanów 0, odczyty logiczne 78372 , odczyty fizyczne 0, odczyty z wyprzedzeniem 0, odczyty logiczne LOB 0, odczyty fizyczne LOB 0, odczyty LOB z wyprzedzeniem 0.

Tabela „Faktury”. Liczba skanów 1, odczyty logiczne 11400, odczyty fizyczne 0, odczyty z wyprzedzeniem 0, odczyty logiczne LOB 0, odczyty fizyczne LOB 0, odczyty z wyprzedzeniem LOB 0.

(70510 wierszy dotyczy)

Indeks:dane wyjściowe z włączoną funkcją STATISTICS IO:

Tabela „Faktury1”. Liczba skanów 0, odczyty logiczne 81119 , odczyty fizyczne 0, odczyty z wyprzedzeniem 0, odczyty logiczne LOB 0, odczyty fizyczne LOB 0, odczyty LOB z wyprzedzeniem 0.

Stół „Stół roboczy”. Liczba skanów 0, odczyty logiczne 0, odczyty fizyczne 0, odczyty z wyprzedzeniem 0, odczyty logiczne lobu 0, odczyty fizyczne lobu 0, odczyty z wyprzedzeniem lobu 0.

Tabela „Faktury”. Liczba skanów 1, odczyty logiczne 11400 , odczyty fizyczne 0, odczyty z wyprzedzeniem 0, odczyty logiczne LOB 0, odczyty fizyczne LOB 0, odczyty LOB z wyprzedzeniem 0.

(70510 wierszy dotyczy)

Dodatkowe informacje

Microsoft i inne źródła dostarczają skrypty do badania środowiska produkcyjnego indeksów i identyfikowania takich sytuacji, jak:

  1. Zbędne indeksy – Zduplikowane indeksy
  2. Brakujące indeksy – Indeksy, które mogą poprawić wydajność w oparciu o obciążenie pracą
  3. Stoły – Tabele bez indeksów klastrowych
  4. Nadmiernie indeksowane tabele – Tabele z większą liczbą indeksów niż kolumn
  5. Użycie indeksu – Liczba wyszukiwań, skanów i wyszukiwań w indeksach

Pozycje 2, 3 i 5 są bardziej związane z wpływem na wydajność w odniesieniu do odczytów, podczas gdy pozycje 1 i 4 dotyczą wpływu na wydajność w odniesieniu do zapisów. Listingi 4 i 5 to dwa przykłady tych publicznie dostępnych zapytań.

-- LISTING 4 Sprawdź nadmiarowe indeksy;WITH INDEXCOLUMNS AS(SELECT DISTINCTSCHEMA_NAME (O.SCHEMA_ID) AS 'SCHEMANAME', OBJECT_NAME(O.OBJECT_ID) AS TABLENAME,I.NAME AS INDEXNAME, O.OBJECT_ID,I.INDEX_ID, I.TYPE, (WYBIERZ CASE KEY_ORDINAL WHEN 0 THEN NULL ELSE '['+COL_NAME(K.OBJECT_ID,COLUMN_ID) +']' END AS [DATA()]FROM SYS.INDEX_COLUMNS AS K WHERE K.OBJECT_ID =I.OBJECT_ID AND K.INDEX_ID =I.INDEX_IDORDER BY KEY_ORDINAL, COLUMN_ID FOR XML PATH('')) JAKO COLSFROM SYS.INDEXES JAK WEWNĘTRZNE ŁĄCZENIE SYS.OBJECTS O ON I.OBJECT_ID =O.OBJECT_ID INNER JOIN SYS.INDEX_COLUMNS IC ON IC. OBJECT_ID =I.OBJECT_ID AND IC.INDEX_ID =I.INDEX_IDINNER JOIN SYS.COLUMNS C ON C.OBJECT_ID =IC.OBJECT_ID AND C.COLUMN_ID =IC.COLUMN_IDGDZIE I.OBJECT_ID IN (WYBIERZ OBJECT_ID Z TYPU SYS.OBJECTS WHERE ') AND I.INDEX_ID <>0 ORAZ I.TYPE <>3 ORAZ I.TYPE <>6GRUP ​​WEDŁUG O.SCHEMA_ID,O.OBJECT_ID,I.OBJECT_ID,I.NAME,I.INDEX_ID,I.TYPE) WYBIERZ IC1 .NAZWASCHEMATU,IC1.NAZWATABELI,IC1.INDEXNAME,IC1.COLS AS INDEXCOLS,IC2.INDEXNAME AS REDUNDANTINDEX NAZWA, IC2.COLS AS REDUNDANTINDEXCOLSFROM INDEXCOLUMNS IC1JOIN INDEXCOLUMNS IC2 ON IC1.OBJECT_ID =IC2.OBJECT_IDAND IC1.INDEX_ID <> IC2.INDEX_IDAND IC1.COLS <> IC2.COLSAND IC2.COLS LIKE REPLACE(IC1.'COLS,'[ [[]') + ' %'ORDER BY 1,2,3,5;-- LISTING 5 Sprawdź indeksy UżycieSELECT O.NAME AS TABLE_NAME, I.NAME AS INDEX_NAME, S.USER_SEEKS, S.USER_SCANS, S.USER_LOOKUPS, S.USER_UPDATESFROM SYS.DM_DB_INDEX_USAGE_STATS SINNER JOIN SYS.INDEXES ION I.INDEX_ID=S.INDEX_IDAND S.OBJECT_ID =I.OBJECT_IDINNER JOIN SYS.OBJECTS OON S.OBJECT_ID =O.OBJECT_IDSYS.;

Wniosek

Za pomocą Query Store pokazaliśmy, że dodatkowe obciążenie indeksem może wprowadzić do planu wykonania przykładowej instrukcji insert. W środowisku produkcyjnym nadmierne i nadmiarowe indeksy mogą mieć negatywny wpływ na wydajność, szczególnie w bazach danych przeznaczonych dla obciążeń OLTP. Ważne jest, aby korzystać z dostępnych skryptów i narzędzi do badania indeksów i określania, czy rzeczywiście pomagają, czy szkodzą wydajności.

Przydatne narzędzie:

dbForge Index Manager – poręczny dodatek SSMS do analizy stanu indeksów SQL i rozwiązywania problemów z fragmentacją indeksów.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Testowanie warstwy ODBC

  2. Złożoność NULL – Część 3, Brakujące standardowe funkcje i alternatywy T-SQL

  3. Opcje dostrajania wydajności bazy danych SQL Azure

  4. Kopia zapasowa / eksport bazy danych z SSH

  5. 11 typowych instrukcji SQL z podstawowymi przykładami