#sql #sql-server #sql-optimization
#sql #sql-сервер #sql-оптимизация
Вопрос:
Есть ли простой способ объединить приведенный ниже SQL в 1 инструкцию? Идентификатор фильтра может иметь нулевую длину, поэтому Filters
таблица является необязательной. Итак, если нет лучшего способа сделать это, я «вынужден» использовать приведенную ниже логику EXISTS.
Я уже понимаю…
Я уже понимаю, что могу создать динамическую строку и использовать EXEC
для ее запуска … но это медленно.
Отношение Document-to-DocumentMetadata равно: 1 Document
ко многим DocumentMetadata
Отношение Filter-to-DocumentMetadata равно: 1 ко многим Filter
DocumentMetadata
SQL выглядит следующим образом:
DECLARE @SearchTerms NVARCHAR(MAX)
DECLARE @FilterIDs VARCHAR(100)
SET @SearchTerms = '7%'
SET @FilterIDs = '12'
------------------------
DECLARE @Filters TABLE (FilterID int)
IF(@FilterIDs IS NOT NULL)
INSERT INTO @Filters SELECT items AS INT FROM Split(@filterIDs, ',')
IF EXISTS(SELECT FilterID FROM @Filters)
BEGIN
SELECT
Document.ID AS DocumentID
,Document.SourceID
,Document.Name
,Document.Title
,Document.DocumentUrl
,Document.DocType
,Document.DocumentModifiedDate
,Document.Library
,DocumentMetadata.ID AS DocumentMetadataID
,DocumentMetadata.DocumentID
,DocumentMetadata.FilterID
,DocumentMetadata.Value
FROM Document
JOIN DocumentMetadata
ON DocumentMetadata.DocumentID = Document.ID
JOIN Filter
ON Filter.ID = DocumentMetadata.FilterID
AND Filter.ID IN (SELECT FilterID FROM @Filters)
WHERE
Document.Name LIKE @SearchTerms
OR Document.Title LIKE @SearchTerms
ORDER BY
Document.Name, Document.Title
END
ELSE
BEGIN
SELECT
Document.ID AS DocumentID
,Document.SourceID
,Document.Name
,Document.Title
,Document.DocumentUrl
,Document.DocType
,Document.DocumentModifiedDate
,Document.Library
,DocumentMetadata.ID AS DocumentMetadataID
,DocumentMetadata.DocumentID
,DocumentMetadata.FilterID
,DocumentMetadata.Value
FROM Document
JOIN DocumentMetadata
ON DocumentMetadata.DocumentID = Document.ID
JOIN Filter
ON Filter.ID = DocumentMetadata.FilterID
WHERE
Document.Name LIKE @SearchTerms
OR Document.Title LIKE @SearchTerms
ORDER BY
Document.Name, Document.Title
END
Ответ №1:
JOIN Filter ON Filter.ID = DocumentMetadata.FilterID
AND (Filter.ID IN (SELECT FilterID FROM @Filters) OR @FilterIDs is null)
Это должно касаться того, есть ли у вас элементы в таблице @filters или у вас было введено значение null для filtersID (которое управляет таблицей Filters). В случае, если в предложении OR указано значение null, запись пропускается, поэтому она полагается на другую часть предложения join, которая является общей для ваших операторов. Это должно позволить вам просто использовать 1 предложение select для покрытия обоих.
Комментарии:
1. Обратите внимание, что этот метод может снизить производительность на больших наборах данных; для таблиц меньшего размера это нормально (anc, безусловно, проще в обслуживании).
2. @Stuart У тебя есть другой способ?
3. Если количество элементов в @Filters довольно велико, то это может пострадать, но при небольших числах все будет в порядке.
4. @Andrew Из любопытства, насколько высок «довольно высокий» … 5, 30, 100?
5. Я помню, что на SQL Server 2005 RTM поведение плана запроса изменилось в 64 элементах, позже это изменилось — лучший подход — запустить несколько тестов с вашими данными. Я бы также отметил, что целью было решить двойные операторы — использование IN для большого количества значений — это другой вопрос, и я почти уверен, что он поднимался на SO несколько раз раньше