【发布时间】:2019-04-02 20:32:59
【问题描述】:
让我打开:
数据库“MyDatabase”中的 SHOWPLAN 权限被拒绝。
说完这些,我会布置一下我的情况。
所以,我使用的数据库有一个执行速度相当快的视图。
SELECT * FROM MyView
在 1 秒内返回 32 行,并包含我需要过滤的值 (ID) 的非索引列。
如果我直接在视图中过滤这些 ID:
SELECT * FROM MyView WHERE MyView.SomeId = 18
速度非常慢,返回具有该 ID 的 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_CODE 的 PROC_ID,因此有必要将 CMP 的 PROC_CODE 范围转换为一组 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
【问题讨论】:
-
看来问题出在
MyView(您还没有向我们展示代码)。 -
如果你可以访问sys表,你可以查询执行计划,一旦你点击xml结果,它将在新窗口中为你打开执行计划。
-
这对我来说是新的。让我看看我能挖出什么。
-
无权查看执行计划并不是“碍事”。如果您的公司确定您需要解决性能问题,那么他们需要让您访问允许您执行此操作的工具。另一种选择是将您的查询发送给高级和强大的 DBA,并告诉他们您需要他们来运行它并向您发送实际的执行计划,因为您无权访问。大约在您第二次这样做时,您将神奇地获得访问权限。解决性能问题的方法不是通过反复试验,而是通过分析执行。而这方面的工具就是执行计划。
-
请包含
MyView的定义。没有它,我们真的不可能提供帮助。当您添加过滤条件时,SQL 优化器很可能选择了错误的索引。表格统计信息是最新的吗?
标签: sql sql-server performance temp-tables sql-view