Позвольте мне открыть с помощью:
Отказано в разрешении SHOWPLAN в базе данных 'MyDatabase'.
После этого я разметлю свою ситуацию.
Итак, база данных, с которой я работаю, имеет представление, которое выполняется довольно быстро.
SELECT * FROM MyView
возвращает 32 строки в 1 секунду и содержит неиндексированный столбец значений (идентификаторов), который мне нужендля фильтрации.
Если я отфильтрую эти идентификаторы непосредственно в представлении:
SELECT * FROM MyView WHERE MyView.SomeId = 18
Все очень замедляется, и для возврата 20 строк с этим идентификатором требуется 21 секунда.
В качестве эксперимента я поместил нефильтрованные результаты во временную таблицу и выполнил отфильтрованный запрос к временной таблице:
IF OBJECT_ID('tempdb..#TEMP_TABLE') IS NOT NULL
BEGIN
DROP TABLE #TEMP_TABLE
END
SELECT * INTO #TEMP_TABLE
FROM MyView;
SELECT *
FROM #TEMP_TABLE
WHERE #TEMP_TABLE.SomeId = 18
DROP TABLE #TEMP_TABLE
И обнаружил, что отфильтрованные результаты возвращаются гораздо быстрее (примерно 1 секунда)
Существует ли более чистый синтаксис или шаблон, который можно реализовать для достижения той же производительности?
ОБНОВЛЕНИЕ: Просмотр определения и описания
Обфусцирование вручную,но я был осторожен, так что, надеюсь, не так много ошибок.Все еще ожидает разрешения SHOWPLAN, поэтому план выполнения еще не завершен.
Цель представления состоит в том, чтобы обеспечить подсчет всех записей, принадлежащих определенному компоненту (CMP.COMPONENT_ID = '100'), сгруппированных по местоположению.
«Принадлежность» определяется тем, что запись PROC_CODE (отображенная через PROC_ID) находится в пределах диапазона включения CMP (CMP_INCs), а не в диапазоне исключения CMP (CMP_EXCs).
На практике диапазоны исключения создаются для отдельных кодов (границы всегда равны), что делает достаточным проверку того, что код не равен границе.
PROC_CODES может (и не можетвсегда) имеют буквенный префикс или суффикс, что делает необходимым сравнение ISNUMERIC ().
Хранилища записей PROC_ID для их PROC_CODE, поэтому необходимо преобразовать диапазоны PROC_CODE CMP в набор PROC_ID для определения, к каким записям принадлежатк этому компоненту
Проблема производительности возникает при попытке фильтрации по DEPARTMENT_ID или LOCATION_ID
[CO_RECORDS] также является представлением, но если это настолько глубоко, я расскажу об этом кому-то с меньшими затратамикрасная лента для борьбы.
CREATE VIEW [ViewsSchema].[MyView] AS
WITH
CMP_INCs AS (SELECT RNG.*, COALESCE(RNG.RANGE_END, RNG.RANGE_BEG) [SAFE_END] FROM DBEngine.DBO.DB_CMP_RANGE [RNG] WHERE [RNG].COMPONENT_ID = '100'),
CMP_EXCs AS (SELECT CER.* FROM DBEngine.DBO.DB_CMP_EXC_RANGE CER WHERE CER.COMPONENT_ID = '100'),
CMP_PROC_IDs AS (
SELECT
DBEngine_ProcTable.PROC_ID [CMP_PROC_ID],
DBEngine_ProcTable.PROC_CODE [CMP_PROC_CODE],
DB_CmpTable.COMPONENT_ID [CMP_ID],
MAX(DB_CmpTable.COMPONENT_NAME) [CMP_NAME]
FROM [DBEngine].DBO.DBEngine_ProcTable DBEngine_ProcTable
LEFT JOIN CMP_INCs ON ISNUMERIC(DBEngine_ProcTable.PROC_CODE) = ISNUMERIC(CMP_INCs.RANGE_BEG)
AND(DBEngine_ProcTable.PROC_CODE = CMP_INCs.RANGE_BEG
OR DBEngine_ProcTable.PROC_CODE BETWEEN CMP_INCs.RANGE_BEG AND CMP_INCs.SAFE_END)
INNER JOIN DBEngine.DBO.DB_CmpTable ON CMP_INCs.COMPONENT_ID = DB_CmpTable.COMPONENT_ID
LEFT JOIN CMP_EXCs EXCS ON EXCS.COMPONENT_ID = DB_CmpTable.COMPONENT_ID AND EXCS.EXCL_RANGE_END = DBEngine_ProcTable.PROC_CODE
WHERE EXCS.EXCL_RANGE_BEG IS NULL
GROUP BY
DBEngine_ProcTable.PROC_ID,
DBEngine_ProcTable.PROC_CODE,
DBEngine_ProcTable.BILL_DESC,
DBEngine_ProcTable.PROC_NAME,
DB_CmpTable.COMPONENT_ID
)
SELECT
RECORD.LOCATION_NAME [LOCATION_NAME]
, RECORD.LOCATION_ID [LOCATION_ID]
, MAX(RECORD.[Department]) [DEPARTMENT]
, RECORD.[Department ID] [DEPARTMENT_ID]
, SUM(RECORD.PROCEDURE_QUANTITY) [PROCEDURE_COUNT]
FROM DBEngineCUSTOMRPT.ViewsSchema.CO_RECORDS [RECORDS]
INNER JOIN CMP_PROC_IDs [CV] ON [CV].CMP_PROC_ID = [RECORDS].PROC_ID
CROSS JOIN (SELECT DATEADD(M, DATEDIFF(M, 0,GETDATE()), 0) [FIRSTOFTHEMONTH]) VARS
WHERE [RECORDS].TYPE = 1
AND ([RECORDS].VOID_DATE IS NULL OR [RECORDS].VOID_DATE >= VARS.[FIRSTOFTHEMONTH] )
AND [RECORDS].POST_DATE < VARS.[FIRSTOFTHEMONTH]
AND [RECORDS].DOS_MONTHS_BACK = 2
GROUP BY [RECORDS].LOCATION_NAME, [RECORDS].[Department ID]
GO