Database
 sql >> база данни >  >> RDS >> Database

Подход към настройката на индекса – част 2

В последната си публикация започнах да очертавам процеса, през който преминавам, когато настройвам заявки – особено когато открия, че трябва да добавя нов индекс или да променя съществуващ. До този момент идентифицирахме проблемната заявка, индекса, който ми трябва, какви индекси съществуват в момента в таблицата и дали тези индекси се използват или не. След като имаме тези данни, можем да преминем към следващите стъпки в процеса.

Стъпка 5:Какво използва индекс

Освен че виждате колко често се използва даден индекс (или не), е полезно да знаете какви заявки използвам индекс, особено ако искам да го слея с друг индекс. За щастие Джонатан Кехайяс вече е написал заявка, за да помогне да се идентифицира кои планове използват конкретен индекс. Неговата версия може да се използва за кеша на плана – единственото предизвикателство там е, че информацията е преходна, така че може да не улавяте всяка заявка, която използва конкретен индекс. Query Store може да помогне с това – промених заявката му, за да получа същата информация от плановете в 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);

Струва си да се отбележи, че това е друга точка, в която мога да се озова много дълбоко в заешка дупка, в зависимост от броя на индексите, които преглеждам, и броя на заявките, които ги използват. Ако е възможно, ще взема предвид и броя на изпълнението (от Query Store или кеша на плана), за да не разбирам само какво заявката използва индекс, но колко често се изпълнява тази заявка. Това е мястото, където настройката на индекса се превръща в изкуство. Мога да събера смешно количество данни... но нямам безкрайно време за анализ, така че трябва да преценя колко заявки ще прегледам.

Стъпка 6:Тестване

Най-просто, тестването на индекс означава приемане на проблемната заявка и улавяне на данните за плана и производителността (продължителност, IO, CPU и т.н.), а след това създаване на индекса, повторно изпълнение на заявката и улавяне на същата информация. Ако производителността се подобри, можете да тръгнете!

Рядко е толкова просто.

Като начало, често имам поне два варианта на индекс, който искам да тествам, понякога повече. Започвам с моята базова линия, след това създавам всички варианти на индекса, изчиствам кеша на плана и виждам какво избира SQL Server. След това превъртам и принуждавам всеки индекс с намек, улавяйки плана и показателите за ефективност за всяко изпълнение. Забележка:това предполага, че имам достатъчно дисково пространство за всички индекси... ако не, тогава ги създавам един по един и тествам. Накрая сравнявам числата. Ако просто добавям нов индекс, почти съм готов. Но ако променя индекс или обединявам двойка, може да стане сложно.

В идеалния свят, ако променя съществуващ индекс, намирам най-честите/важни заявки, които използват текущия индекс и получавам техните планове и показатели за ефективност (това е лесно с Query Store). След това променям индекса, стартирам всички тези заявки отново и виждам дали ще получа значителни промени във формата на плана и/или производителността.

Ако слея два индекса, правя същото нещо, но с всички заявки, които използват всеки индекс, и след това тествам отново с обединения индекс.

Ако добавям/променям/сливам множество индекси за таблица, тогава трябва да получа всички подходящи заявки и техните планове и показатели, да променя индексите, след което да получа цялата информация отново и да сравня. Това може да отнеме много време, в зависимост от това колко различни заявки има. Тук това е форма на изкуство и трябва да определите колко заявки наистина трябва да тествате. Това е функция от честотата на изпълнение, важността/уместността на заявката и времето, което имам на разположение/разпределено.

И накрая, ако добавя индекс към таблица и не премахна съществуващите, тогава съм добавил допълнителни разходи за INSERT, DELETE и потенциално UPDATE. Тази промяна е възможна за тестване на производителността, но ви е необходима тестова среда и възможност за провеждане на тест за натоварване и заснемане на показатели преди и след промяната, свързани с продължителност, IO и CPU.

Има много приятели, поради което е ирония, че първоначално се сетих да заявя, че настройката на индекса е лесна. Може не винаги да е просто, но е възможно. Това е въпрос на старание и следене на всичко.

Стъпка 7:Внедряване

След като проверих новите индекси, доколкото е възможно, ние сме готови за производство. Признавам, че разглеждам промените в индекса като нискорискови, особено новите. Ако е проблем, можете да го пуснете незабавно и да се върнете към първоначалното състояние. Със сценарий за промяна/сливане/изпускане, вие искате всичко да е скриптирано, така че можете да променяте и пресъздавате индекси, ако е необходимо, за да нулирате индексите. Винаги препоръчвам първоначално да деактивирате индексите, вместо да ги изпускате, тъй като тогава не е нужно да се притеснявате за дефиницията – ако трябва да добавите индекса обратно, просто го изграждате отново.

Резюме

Вашият метод за добавяне и/или консолидиране на индекси може да е различен! Точно като настройката на заявката, няма перфектен процес. За всеки, който е начинаещ в настройката на индекса, това се надяваме да предостави начало на елементи за преглед и важни съображения. Невъзможно е да се добавят индекси, без да се добавят допълнителни разходи – и отново тук идва изкуството:трябва да определите дали ползата от индекса надвишава цената му за модификации.

Настройката на индекса е постоянен, итеративен процес – не мисля, че някога сте свършили, защото се променят кода, добавят се нови таблици или функционалност и данните в таблиците се променят. Кимбърли има две публикации (https://www.sqlskills.com/blogs/kimberly/spring-cleaning-your-indexes-part-i/ и https://www.sqlskills.com/blogs/kimberly/spring-cleaning- your-indexes-part-ii/), които говорят за почистване на вашите индекси — сега е подходящо време да започнете! И накрая, когато някой попита „колко индекса трябва да има за таблица?“ Отговарям с нещо от рода на „най-малкото число, от което се нуждаете, за да удовлетворите възможно най-много заявки“. Няма магическо число — виждал съм таблици с нулеви индекси и съм виждал таблици с над 100 (сигурен съм, че някои от вас са виждали по-висок брой). Нито нула, нито 100 са добри, но „правилното“ число е това, което трябва да разберете, като използвате наличните данни и вашия опит.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Разбиране на транзакциите в SQL

  2. Разбиране на типове и формати на MapReduce

  3. Как да създадете съхранени процедури в SQL?

  4. Използване на модели на работния поток за управление на състоянието на всеки обект

  5. Възстановете копие на вашата база данни