Запрос быстрый, но в VIEW он медленный из-за ROW_NUMBER

У меня есть запрос, который при запуске дает мгновенный результат.

Однако я вставляю точно такой же запрос в VIEW, и для ответа требуется 6 секунд.

Например,

SELECT ... FROM MyTables WHERE PersonID = x

работает быстро.

Но создайте представление с помощью:

SELECT ... FROM MyTables 

А затем вызовите представление:

SELECT * FROM MyView WHERE PersonID = x

И работает медленно.

Фактический запрос:

select ROW_NUMBER() over(partition by h.Id order by h.[SysStartTime]) as VersionNUmber,
      h.Id,
      fac.HIC,
      ... plus 18 other columns from the joined tables.

from   [hist].[A_View] as h
inner join [dbo].[Facilities] as fac
      on fac.Id = h.FacilityId
inner join ref.FormStatus as r_fs
      on r_fs.Id = h.FormStatusId
inner join TableA as data
      on data.Id = h.dataId
inner join Consultants as c
      on c.Id = h.ConsultantId
inner join dbo.Specialties spec
      on spec.Id = h.SpecialtyId
inner join dbo.Users modifieduser
      on modifieduser.Id = h.ModifiedByUserId
left join ref.ARefTable as r_uc
      on r_uc.Id = h.refId
cross apply [dbo].[getPersonUrn](h.PersonId, h.AnotherIdId) as PersonURN

(Обратите внимание, я меняю имена некоторых таблиц и столбцов, так как мы находимся в довольно конфиденциальной области)

Я заметил, что в 97% случаев это происходит в сортировке (Top N Sort) при выполнении представления. В запросе, что 34%, но планы совсем другие.

Я подозревал обнюхивание параметров, но не думаю, что это проблема с представлениями.

Я на самом деле только что «исправил» это, но понятия не имею, почему.

Мой первый столбец в моем выборе - ROW_NUMBER.

SELECT ROW_NUMBER() over(partition by h.Id order by h.[SysStartTime]) as` VersionNumber,

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


person Craig    schedule 14.12.2016    source источник
comment
Вы проверили план выполнения? Вы можете включить план выполнения с панели инструментов. После запуска запроса вы можете перейти на вкладку плана выполнения и посмотреть, что происходит.   -  person KrishnaDhungana    schedule 14.12.2016
comment
Я сделал это, и именно так я сообщил в 97% случаев, это в сортировке (Top N Sort).   -  person Craig    schedule 14.12.2016
comment
Вы используете предложения top или order by? Можете ли вы опубликовать актуальные запросы, сценарий таблицы и планы выполнения? Вы оба запускаете в ssms?   -  person under    schedule 14.12.2016
comment
Добавлен фактический запрос просмотра.   -  person Craig    schedule 14.12.2016
comment
У вас есть row_number() в запросе, который выполняется мгновенно? Просто убедитесь, что вы сравниваете яблоки с яблоками.   -  person sstan    schedule 14.12.2016
comment
Версия, которая работает медленно, имеет номер ROW_NUMBER. Удалите это, а затем запустите представление, и оно будет медленным. Этот запрос выше — это запрос из представления.   -  person Craig    schedule 14.12.2016


Ответы (2)


1) Здесь ROW_NUMBER применяется только к отфильтрованным данным:

SELECT ROW_NUMBER(), ... FROM MyTables WHERE PersonID = x

Сначала он фильтрует по PersonID, затем вычисляет ROW_NUMBER

2) Здесь ROW_NUMBER применяется ко всем данным:

CREATE VIEW MyView as
  select ROW_NUMBER(), ... FROM MyTables

SELECT * FROM MyView WHERE PersonID = x

и только после обработки полных данных применяется фильтр по PersonID

это то же самое, что

SELECT * FROM
(SELECT ROW_NUMBER(), ... FROM MyTables
) t
WHERE t.PersonID = x

посмотрите пример:

GO
CREATE VIEW dbo.test_view
AS
    SELECT ROW_NUMBER() OVER (ORDER BY NAME) rn, o.name, o.[object_id]
    FROM sys.objects o
GO
SET SHOWPLAN_XML ON
GO
SELECT rn, o.name, o.[object_id] FROM dbo.test_view o
WHERE OBJECT_ID < 100
GO
SELECT ROW_NUMBER() OVER (ORDER BY NAME) rn, o.name, o.[object_id] FROM sys.objects o
WHERE OBJECT_ID < 100
GO
SET SHOWPLAN_XML OFF
GO
DROP VIEW dbo.test_view
GO

С видом filter операция в самом конце. Поэтому на самом деле планы другие.

person Ivan Starostin    schedule 14.12.2016

Я обнаружил, что при запуске в представлении он подсчитывает каждую запись с помощью ROW_NUMBER(), а затем выбирает. Когда вы запускаете его в запросе, он просто подсчитывает записи, возвращаемые с помощью ROW_NUMBER().

person Omzig    schedule 07.10.2020