Как избежать сканирования таблицы на SQL сервере в этой ситуации - PullRequest
0 голосов
/ 27 марта 2020

Есть две таблицы, Costs и Logs. Данные в таблице Costs могут быть в миллионах строк, а в таблице Logs это могут быть миллиарды строк.

Мне нужно обновить столбец CostBy в таблице Costs в виде задача обслуживания в производственной среде в пределах 100 записей при каждом запуске.

CREATE TABLE Cost
(
    C_PK uniqueidentifier primary key not null,
    C_CostBy varchar(3) not null
)

CREATE TABLE Logs
(
    L_PK uniqueidentifier primary key not null,
    L_ParentTable varchar(255) not null,  -- Table Cost and other table's name
    L_ParentID uniqueidentifier not null, -- Cost's pk and other table's pk
    L_Event varchar(3) not null, -- Part are 'ADD' and other event types
    L_User varchar(3) not null 
 )

CREATE NONCLUSTERED INDEX [L_ParentID] 
    ON [dbo].[Costs] ([L_ParentID] ASC)

Вот исходный оператор обновления:

UPDATE TOP(100) Costs
SET CostBy = ISNULL(L_User, '~UK')
FROM Costs
LEFT JOIN Logs ON L_ParentID = C_PK AND L_Event = 'ADD'
WHERE CostBy = ''

Однако этот оператор приводит к серьезной проблеме производительности, высокой стоимости таблицы сканирование в таблице Costs.

Мой вопрос: как избежать сканирования таблицы в таблице Costs или как оптимизировать оператор обновления?

Заранее спасибо.

1 Ответ

0 голосов
/ 27 марта 2020

Возможно, вы захотите попробовать следующее.

Сначала создайте индекс в журналах, включая все соответствующие столбцы:

CREATE INDEX ix ON Logs 
(
  L_Parent_ID -- join condition, variable
)
INCLUDE 
(
  L_User -- no filter condition, but you use it your update
)
WHERE 
(
  L_Event = 'ADD' -- join condition, constant
)

Если это уникальный индекс, ie , только одна строка будет когда-либо существовать с событием ADD для данного родительского идентификатора, убедитесь, что этот индекс уникален, так как он может значительно повысить производительность.

Во-вторых, и это ситуация, когда вы попадете, вы можете Попробуйте с индексом Costs (CostBy), потому что вы ищете только пустые значения CostBy для обновления. Этот индекс нужно будет обновить по вашему запросу, потому что он обновляет его, поэтому он может замедлить ваш запрос, а не ускорить его. Это зависит от ряда факторов.

Если у вас есть корпоративная лицензия, попробуйте оба варианта с WITH (DATA_COMPRESSION = PAGE), это может значительно сократить время ввода-вывода за счет ЦП. Это зависит от вашего узкого места.

Кроме того, в зависимости от характера ваших данных, обновление статистики может улучшить ваши запросы. Если количество строк с CostBy = '' слишком велико по сравнению с другими значениями, вы можете воспользоваться полной статистикой по этому полю. Рассмотрим NORECOMPUTE, если они вам нужны только для этого конкретного c запроса, на этот раз.

CREATE STATISTICS st_Costs_CostBy
ON Costs (CostBy)  
WITH FULLSCAN, NORECOMPUTE;  
...