使用'except'进行查询优化
Posted
技术标签:
【中文标题】使用\'except\'进行查询优化【英文标题】:Query Optimization using 'except'使用'except'进行查询优化 【发布时间】:2021-10-20 17:28:44 【问题描述】:我最近一直在进行一些性能优化,但对下面的查询有点卡住了。分解一下,各个步骤似乎不需要很长时间,但是当我将查询作为一个整体运行时,大约需要 30 分钟才能完成。
TABLE 有大约 100k 行,而 VIEW 有大约 400k 行,所以它们不是特别大。我不确定我是否只是没有准确理解 EXCEPT 逻辑,这是否可能是罪魁祸首?除了 EXCEPT 之外,还有其他选择吗?
编辑 - 视图本身有大约 4 个连接和一个 UNION,所以它确实有一些逻辑。
CREATE TABLE [SCHEMA].[TABLE](
ColumnA [int] IDENTITY(1,1) NOT NULL,
ColumnB [tinyint] NOT NULL,
ColumnC [tinyint] NOT NULL,
ColumnD [int] NULL,
ColumnE [nvarchar](50) NOT NULL,
ColumnF [int] NOT NULL,
ColumnG [nvarchar](250) NULL,
ColumnH [nvarchar](250) NULL,
ColumnI [nvarchar](250) NULL,
ColumnJ [nvarchar](50) NULL,
columnK [nvarchar](400) NULL,
ColumnL [nvarchar](2) NULL,
ColumnM [nvarchar](250) NULL,
ColumnN [nvarchar](3) NULL,
----
DELETE FROM [DB].[SCHEMA].[TABLE] WHERE ColumnB NOT IN (4,6)
AND ColumnG not in
(SELECT ColumnG
FROM
(
SELECT ColumnG,ColumH,ColumnI FROM [DB].[SCHEMA].[TABLE] EXCEPT
SELECT ColumnG,ColumnH,ColumnI FROM [DB].[SCHEMA].[VIEW]
WHERE VIEW.ColumnB='Active' and year(LastChgDateTime) = 9999
) AAA )
感谢您的帮助!
【问题讨论】:
year(LastChgDateTime)
不会高效,因为它不是 SARGable。使用LastChgDateTime >= '99990101
。
问题可能是视图中的基础查询。视图是否复杂?
抱歉,刚刚添加了关于视图的内容。它有大约 4 个连接和一个 UNION。不确定您是否会将其标记为复杂。
4 个连接和一个 UNION 肯定很复杂,您是否检查过您的 UNION 是否真的需要删除重复项?那是一种昂贵的 DISTINCT SORT,10 次中有 9 次根本不可能是骗子,他们应该使用 UNION ALL 而不必执行这些排序。
9999 的假日期/年份往往迟早会导致问题。
【参考方案1】:
不知道您的架构和索引,很难说。我们还没有看到查询计划。而且您还没有提供视图定义,所以我们不知道这涉及到什么。
但首先,您可以通过以下方式简化此查询
注意在
LastChgDateTime
上使用 sarge-able 谓词
DELETE FROM [DB].[SCHEMA].[TABLE]
WHERE ColumnB NOT IN (4,6)
AND NOT EXISTS (
SELECT ColumnG,ColumH,ColumnI
FROM [DB].[SCHEMA].[TABLE] AAA
WHERE AAA.ColumnG = [TABLE].ColumnG
EXCEPT
SELECT ColumnG,ColumnH,ColumnI
FROM [DB].[SCHEMA].[VIEW]
WHERE [VIEW].ColumnB = 'Active' and LastChgDateTime >= '9999-01-01'
);
对于上述情况,以下索引是有意义的
视图需要在基表上建立索引
[TABLE] (ColumnG, ColumH, ColumnI) INCLUDE (ColumnB)
[VIEW] (ColumnB, ColumnG, ColumH, ColumnI, LastChgDateTime)
我们可以通过使用带有窗口函数的可更新 CTE 来进一步优化。
我不完全确定您要实现的逻辑,但它似乎是这样的。
WITH cte AS (
SELECT
t.*,
IsGNotInView = COUNT(v.IsNotInView) OVER (PARTITION BY t.ColumnG)
FROM [DB].[SCHEMA].[TABLE] t
CROSS APPLY (
SELECT
CASE WHEN NOT EXISTS (SELECT 1
FROM [DB].[SCHEMA].[VIEW] v
WHERE v.ColumnB = 'Active'
AND v.LastChgDateTime >= '9999-01-01'
AND v.ColumnG = t.ColumnG
AND v.ColumnH = t.ColumnH
AND t.ColumnI = v.ColumnI
)
THEN 1 END
) v(IsNotInView)
)
DELETE FROM cte
WHERE ColumnB NOT IN (4,6)
AND IsGNotInView = 0;
【讨论】:
以上是关于使用'except'进行查询优化的主要内容,如果未能解决你的问题,请参考以下文章