#sql #sql-server #performance #select #sql-like
#sql #sql-server #Производительность #выберите #sql-подобный
Вопрос:
Как я могу улучшить следующий запрос SQL Server?
SELECT SUM(Qty)
FROM Products
WHERE Type = 'SODA'
AND (Code LIKE 'A5%'
OR Code IN('DHA2','JHU8','KML2','LQA1','ZSX2'))
Выполнение занимает много времени.
Заранее спасибо.
Я получаю данные из базы данных DB2 через связанный сервер. Я не могу создавать индексы только для чтения.
Id int
Name nvarchar(100)
Type nvarchar(100)
Code nvarchar(100)
Qty int
Комментарии:
1. какова ваша схема таблицы (типы столбцов, индексы)?
2. индексируются ли тип и код?
3. Есть ли индекс в коде столбца? В противном случае оператор Like принудительно выполнит последовательное чтение. Создание плана объяснения поможет определить, где проблема с производительностью.
4. Можете ли вы опубликовать план выполнения вместе с любыми индексами, которые у вас уже есть. Как бы то ни было, если вы запустите этот запрос в среде SQL Server Management Studio с включенной опцией «Включить фактический план выполнения», SQL Server предложит индексы, которые улучшат ваш запрос. Вероятно, это будет гораздо полезнее, чем любой приведенный здесь ответ, поскольку мы ничего не знаем о вашей таблице, только то, что она содержит как минимум 3 столбца (кол-во, тип и код).
5. Вероятный ответ — создать следующий индекс
CREATE NONCLUSTERED INDEX IX_Products_Code ON Products (Code) INCLUDE (Qty) WHERE Type = 'SODA'
— однако этот индекс полностью ориентирован на этот запрос и, вероятно, не сильно поможет в других ваших запросах.
Ответ №1:
Сначала попробуйте создать индекс на products(type, code, qty)
. Это может значительно повысить производительность.
Затем, если это не сработает, попробуйте переписать запрос как:
select sum(qty)
from ((select qty
from products
where type = 'SODA' and
code like 'A5%'
) union all
(select qty
from products
where type = 'SODA' and
code IN ('DHA2','JHU8','KML2','LQA1','ZSX2'))
)
) t;
Это может показаться более сложным, но иногда or
мешает оптимизации запросов.
Комментарии:
1. Человек, который спросил, заявил, что он не может создавать индексы. Так что это неправильный ответ, потому что разделение запроса на два запроса к таблице без индексов приведет к двум полным сканированиям таблицы вместо одного. Таким образом, запрос будет выполняться еще медленнее.
2. @Baltico . , , Если вы посмотрите на историю редактирования, вы увидите, что этот комментарий был вставлен в вопрос после завершения этого ответа.
3. Спасибо, Гордон, я не знал, что это возможно. Конечно, без этого ограничения добавление индексов будет лучшим советом.
Ответ №2:
Это запрос связанного сервера. Вы не указываете, как вы его выполняете, поэтому я предполагаю, что он использует имя связанного сервера в FROM . Если вы посмотрите на план запроса, все, что вы увидите, это Удаленный запрос -> Скалярный компьютер -> Выбрать. Это в основном означает, что все данные, которые вы хотите вычислить, копируются в базу данных tempDB, а затем вычисляются.
Если вы выполняете запрос как EXEC at или OPENQUERY, запрос выполняется удаленно, тогда единственное, что нужно вернуть, это результат.
Попробуйте это:
select *
from
openquery(LinkedServerName, '
SELECT SUM(Qty) Total
FROM Products
WHERE Type = ''SODA''
AND (Code LIKE ''A5%''
OR Code IN(''DHA2'',''JHU8'',''KML2'',''LQA1'',''ZSX2'')) ')
Ответ №3:
Поскольку вы используете связанный сервер, а также проводите сравнение строк, я почти уверен, что ваша низкая производительность связана с тем, что SQL Server должен перенести всю таблицу Product из базы данных DB2 в локальную копию, а затем сравнить строки в соответствии с вашими текущими настройками сортировки. Видите ли, сравнение строк может иметь разные результаты при разных параметрах сортировки и в разных системах баз данных. При соединении между базами данных Microsoft SQL Servers вы можете включить совместимость параметров сортировки, чтобы при выполнении запроса он доверял решению связанного сервера о сравнении и сортировке строк. Я не знаю, возможна ли совместимость параметров сопоставления между Microsoft SQL Server и DB2. Таким образом, решением проблемы будет использование OPENROWSET вместо связанного сервера.
Что-то вроде этого:
SELECT * FROM OPENROWSET
('DB2OLEDB',Netlib=SNA;NetAddr=;NetPort=;RemoteLU=OLYMPIA;LocalLU=LOCAL;ModeName=QPCSUPP;User ID=WNW3XX;Password=WNW3XX;InitCat=OLYMPIA;Default Schema=WNW3XX;PkgCol=WNW3XX;TPName=;Commit=YES;IsoLvl=NC;AccMode=;CCSID=37;PCCodePage=1252;BinAsChar=NO;Data Source=Sample',
'SELECT SUM(Qty)
FROM Products
WHERE Type = ''SODA''
AND (Code LIKE ''A5%''
OR Code IN(''DHA2'',''JHU8'',''KML2'',''LQA1'',''ZSX2'')) ' )
Дополнительные сведения см. в разделе связанный сервер с DB2 с использованием поставщика Microsoft OLE DB для DB2
Ответ №4:
Если это займет так много времени, я предлагаю вам создать таблицу с такой же структурой, затем создать несколько полезных индексов, а затем выполнить запрос к этой локальной таблице:
DELETE FROM Products
INSERT INTO Products
SELECT * FROM RemoteServer.database_name..Products
SELECT SUM(Qty)
FROM Products
WHERE Type = 'SODA'
AND (Code LIKE 'A5%'
OR Code IN('DHA2','JHU8','KML2','LQA1','ZSX2'))