Объединение представлений SQL теряет эффективность

#sql-server

#sql-server

Вопрос:

У меня есть 3 представления:

 View1
ID, A1, A2, A3, A4, ..., Ax

View2
ID, B1, B2, B3, B4, ..., By

View3
ID, C1, C2, C3, C4, ..., Cz
  

У меня также есть временная таблица, содержащая список значений идентификаторов, которые меня интересуют. Если я выполняю запрос между любым представлением и выполняю внутреннее объединение с моей таблицей значений идентификаторов, результаты возвращаются почти сразу.

 select ViewX.*
from #Ids 
inner join ViewX on ViewX.ID = #IDs.ID
  

Однако, если я выполняю комбинацию любых 2 представлений и внутреннего соединения с временной таблицей, то результаты могут занять гораздо больше времени (15-25 секунд).

 select ViewX.*, ViewY.*
from #IDs 
inner join ViewX on ViewX.ID = #IDs.ID
inner join ViewY on ViewY.ID = #IDs.ID
  

Итак, вопрос из двух частей: почему объединение более одного представления занимает намного больше времени и как исправить, чтобы сделать его более эффективным?

Некоторая дополнительная справочная информация; Столбцы View2 и View3 являются вложенными запросами, простое создание нового представления со всеми столбцами из каждого представления становится еще менее эффективным, чем сейчас.

Спасибо


введите описание изображения здесь

Я работал над проблемой и свел ее к одной части. Вот запрос.

     select
        VPayersOrderTracking.*,
        (
            select 
                count(todsdMRID.TOrderDetailsStatusDocumentsId) 
                from #orderDetailsReturn as odrMRID
                inner join TOrderDetailsStatus as todsMRID on todsMRID.TOrderDetailsId = odrMRID.TOrderDetailsId
                inner join TOrderDetailsStatusDocuments as todsdMRID on todsdMRID.TOrderDetailsStatusDocumentsId = todsMRID.TOrderDetailsStatusId 
                inner join LDocumentTypes as ldtMRID on ldtMRID.LDocumentTypesId = todsdMRID.LDocumentTypesId 
                where odrMRID.TOrderDetailsId = odr.TOrderDetailsId and ldtMRID.IsReportTypeDocument = 1
        ) as MedicalReportsIncludingDelectedCount,
        from #orderDetailsReturn as odr
        inner join VPayersOrderTracking on odr.TOrderDetailsId = VPayersOrderTracking.TOrderDetailsId
        inner join VProvidersTrackingDocuments on VProvidersTrackingDocuments.TOrderDetailsId = odr.TOrderDetailsId 
        order by
            VPayersOrderTracking.TOrderHeadersId desc, VPayersOrderTracking.SequenceNumber
  

Если я выполняю этот запрос без вложенного запроса, он возвращает все записи менее чем за 1 секунду. Если я включу запрос, потребуется около 10 секунд, чтобы вернуть то же количество строк. Обычно таких подзапросов было бы 4, что, конечно, пропорционально увеличивает время.

Комментарии:

1. Единственный способ ответить на ваш вопрос — просмотреть ваш план выполнения. Это зависит от вашей настройки, не связанной с упомянутой вами комбинацией временных таблиц представлений. Компонент database Engine создает план выполнения с учетом всего запроса, а представления встроены, т.Е. Представление SQL объединяется в полный запрос. Таким образом, разные комбинации представлений приведут к совершенно разным планам выполнения. Google вставьте план.

Ответ №1:

Возможно, было бы лучше, если бы вы переписали это представление как Inline Table-Valued Function — по сути, это представление с параметрами.

В таком случае вы сможете сначала отфильтровать данные. Например, если вы извлекаете идентификаторы для определенного объекта (страны, языка, бренда и т.д.), Вы сможете передать это значение в качестве параметра в представление и вернуть x% строк вместо 100% строк.

Другой способ оптимизации представления — сделать его индексированным представлением, но есть некоторые требования, поскольку одно из них — не иметь вложенных запросов, как у вас.

Если логика представлений сложна и не может быть переписана, вы можете создать эти представления в виде таблиц, используя триггер или хранимую процедуру для материализации результатов.

И отправной точкой будет совместное использование определений представлений и обращение за помощью для их оптимизации.

Комментарии:

1. Я не администратор базы данных, поэтому я немного не в своей тарелке. Однако то, что вы сказали, заставило меня задуматься, и я смог повысить производительность. Это все еще не то, чего бы мне хотелось. Я думаю, вы правы в том, что логика вложенного запроса — это то, где можно получить наибольшую выгоду. Я покажу часть кода вложенного запроса в следующем комментарии.

2. выберите #temp.OrderID, (выберите count(documents.documentsId) из #temp как статус внутреннего соединения T.OrderID = статус. Документы внутреннего объединения OrderID в status.documentsId = documents.documentsId где T.OrderID = #temp.OrderID и documents.status = 1 ) из #temp

3. @tdinpsp я вижу. Это можно сделать без подзапроса, но я предполагаю, что у вас есть другие подобные подзапросы — если вы можете опубликовать всю инструкцию, я могу попытаться упростить ее.

4. Я добавил, где я нахожусь сегодня выше.