Привет!
Подскажите, пожалуйста, есть задача по объединению\оптимизации индексов. Довольно большая таблица, она есть на нескольких серверах с данными разных компаний (разные клиенты на разных серверах хранятся). Для примерна на одном из серверов в таблице более 600 млн. строк. На таблице есть 2 больших индекса с include. При этом dba жалуется, что некоторые процедуры при использовании этих индексов вызывают загрузку ЦПУ до 90%, если он перекомпилирует процедуру, то она использует кластерный индекс и загрузка ЦПУ падает до 15%.
Я нашла вот этот пост, который позволяет выбрать процедуры из планов в кэше, чтобы определить какие процедуры сейчас используют эти индексы.
[url=]
https://www.sqlskills.com/blogs/jonathan/finding-what-queries-in-the-plan-cache-use-a-specific-index/[/url]
Вот скрипт, который используется
CREATE PROCEDURE spGetPlanUsingIndex
@indexName NVARCHAR(128)
AS
BEGIN
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
-- Make sure the name passed is appropriately quoted
IF (LEFT(@IndexName, 1) <> '[' AND RIGHT(@IndexName, 1) <> ']') SET @IndexName = QUOTENAME(@IndexName);
WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
INSERT INTO [dbo].[LogDataFileIndexUsage]
(
DBName,
SPname,
ScanCount,
SeekCount,
UpdateCount,
RefCount,
UseCount,
QueryPlan,
IndexName
)
SELECT
DB_NAME(E.dbid) AS [DBName],
object_name(E.objectid, dbid) AS [ObjectName],
E.query_plan.value('count(//RelOp[@LogicalOp = ''Index Scan'' or @LogicalOp = ''Clustered Index Scan'']/*/Object[@Index=sql:variable("@IndexName")])','int') AS [ScanCount],
E.query_plan.value('count(//RelOp[@LogicalOp = ''Index Seek'' or @LogicalOp = ''Clustered Index Seek'']/*/Object[@Index=sql:variable("@IndexName")])','int') AS [SeekCount],
E.query_plan.value('count(//Update/Object[@Index=sql:variable("@IndexName")])','int') AS [UpdateCount],
P.refcounts AS [RefCounts],
P.usecounts AS [UseCounts],
E.query_plan AS [QueryPlan],
@IndexName
FROM sys.dm_exec_cached_plans P
CROSS APPLY sys.dm_exec_query_plan(P.plan_handle) E
WHERE
E.query_plan.exist('//*[@Index=sql:variable("@IndexName")]') = 1
OPTION(MAXDOP 1, RECOMPILE);
END
Кроме того попросила дать информацию о missing index на сервере. Список процедур получился небольшим – 10, что интересно одна и та же процедура могла использовать то один индекс то другой. На сервере включен ассинхронный режим обновления статистики. Я выбрала в каких запросах используются эти индексы в процедурах по планам из кэша, и собрала список полей, указанных в SELECT, WHERE и JOIN. А также поля , которые использовались как seek предикаты. Сделала один индекс без include полей, при тестировании вижу такую картину – его использует меньшее число процедур, но скорость работы примерно та же. Я ожидала, что вырастет загрузка CPU, но нет – все ок.
Я понимаю, что убирая include – нужно будет делать Key Lookup чтобы довыбрать нужные поля из таблицы, при анализе плана – можно видеть, что план со старым индексом несколько лучше. Но если изменения позволят сэкономить место + избавят от внезапного изменения загрузки по ЦПУ, то их стоит применить.
Буду благодарна, если поделитесь своими мыслями\опытом решения такой задачи.