使用索引联接临时表

问题描述

我才刚刚开始学习INDEX,听说它可以加快结果,但是我的测试却产生了相反的效果。

有关数据的一些要点:

  • 我的公司使用SQL Server,但除此以外,我对此一无所知
  • 我只是一名员工,没有任何管理员权限,甚至只能查看某些文件夹
  • #TABLE1包含23,000多行,并在1秒内运行
  • #TABLE2包含超过310万行,运行时间约为1.5分钟
  • 使用联接大约需要1.75到2.5分钟
  • 我尝试使用INDEX的过程需要2.5到3或更多
  • 此后我将加入更多表,但这两个表实质上是其他所有表的基础

我在下面尝试的查询比我执行普通的JOIN花费的时间更长

IF OBJECT_ID('tempdb..#TABLE1') IS NOT NULL DROP TABLE #TABLE1;
IF OBJECT_ID('tempdb..#TABLE2') IS NOT NULL DROP TABLE #TABLE2;

SELECT
cast(T1.[ID] as varchar(20)) as 'ID',cast(T1.[Division] as int) as 'Division',cast(T1.[Category] as int) as 'Category',cast(T1.[Platform] as int) as 'Platform',cast(T1.[Condition] as tinyint) as 'Condition',cast(T1.[First Received] as date) as 'First Received',cast(T1.[Last Received] as date) as 'Last Received'

INTO #TABLE1

FROM
CompanyTable as T1

WHERE
T1.[Name] = 'Canada'
AND T1.[Division] = '100';

CREATE NONCLUSTERED INDEX IX_TABLE1 ON #TABLE1([ID],[Division],[Category],[Platform]);

SELECT DISTINCT
SE.[Date] as 'Date',SE.[ID] as 'ID',SE.[Division] as 'Division',SE.[Category] as 'Category',SE.[Platform] as 'Platform',sum(SE.[Units]) as 'Units',sum(SE.[Sales]) as 'Sales',sum(SE.[Retail]) as 'Retail',sum(SE.[Cost]) as 'Cost'

INTO #TABLE2

FROM 
(SELECT
    cast(S1.[Date] as date) as 'Date',cast(S1.[ID] as varchar(20)) as 'ID',cast(S1.[Division] as int) as 'Division',cast(S1.[Category] as int) as 'Category',cast(S1.[Platform] as int) as 'Platform',cast(sum(S1.[Quantity]) * -1 as decimal(38,20)) as 'Units',cast(sum(S1.[Net Amount]) * -1 as decimal(38,20)) as 'Sales',cast(sum(S1.[Cost Amount]) * -1 as decimal(38,20)) as 'Cost',cast(sum(S1.[Price]) as decimal(38,20)) as 'Retail'

    FROM
    SalesTable1 as S1

    WHERE
    S1.[Division] = '100'
    
    GROUP BY
    S1.[ID],S1.[Date],S1.[Division],S1.[Category],S1.[Platform]
    
    UNION ALL
    
    SELECT
    cast(S2.[Date] as date) as 'Date',cast(S2.[ID] as varchar(20)) as 'ID',cast(S2.[Division] as int) as 'Division',cast(S2.[Category] as int) as 'Category',cast(S2.[Platform] as int) as 'Platform',cast(sum(S2.[Quantity]) * -1 as decimal(38,cast(sum(S2.[Net Amount]) * -1 as decimal(38,cast(sum(S2.[Cost Amount]) * -1 as decimal(38,cast(sum(S2.[Price]) as decimal(38,20)) as 'Retail'
    
    FROM
    SalesTable2 as S2
    
    WHERE
    S2.[Division] = '100'
    
    GROUP BY
    S2.[ID],S2.[Date],S2.[Division],S2.[Category],S2.[Platform]
) as T2

GROUP BY
T2.[ID],T2.[Date],T2.[Division],T2.[Category],SE.[Platform]

CREATE NONCLUSTERED INDEX IX_TABLE2 ON #TABLE2([ID],[Platform]);

SELECT *
FROM #TABLE1 as T1
JOIN #TABLE2 as T2 ON T1.[ID] = T2.[ID] AND T1.[Division] = T2.[Division] AND T1.[Category] = T2.[Category] AND T1.[Platform] = T2.[Platform]

DROP INDEX IX_TABLE1 ON #TABLE1;
DROP INDEX IX_TABLE2 ON #TABLE2;

我做错了什么导致它变慢了吗?

解决方法

如下所示在#table1和#table2上创建4个不同的索引,然后运行查询。

CREATE NONCLUSTERED INDEX IX_TABLE1_id ON #TABLE1([ID]);
CREATE NONCLUSTERED INDEX IX_TABLE1_Div ON #TABLE1([Division]);
CREATE NONCLUSTERED INDEX IX_TABLE1_Cat ON #TABLE1([ [Category]);
CREATE NONCLUSTERED INDEX IX_TABLE1_Plt ON #TABLE1([[Platform]);

CREATE NONCLUSTERED INDEX IX_TABLE1_id ON #TABLE2([ID]);
CREATE NONCLUSTERED INDEX IX_TABLE1_Div ON #TABLE2([Division]);
CREATE NONCLUSTERED INDEX IX_TABLE1_Cat ON #TABLE3[ [Category]);
CREATE NONCLUSTERED INDEX IX_TABLE1_Plt ON #TABLE4([[Platform]);
,

您需要在临时表上使用具有唯一值的主键作为CLUSTERED INDEX。然后,您只需要NONCLUSTERED INDEX列上的另一个JOIN。假设ID中的#TABLE1是唯一的,请像这样创建索引:

ALTER TABLE #TABLE1 ADD CONSTRAINT PK_TABLE1 PRIMARY KEY CLUSTERED ([ID]);
CREATE NONCLUSTERED INDEX IX_TABLE1 ON #TABLE1([Division],[Category],[Platform]);

#TABLE2的同上,再次假设ID ID为唯一:

ALTER TABLE #TABLE2 ADD CONSTRAINT PK_TABLE2 PRIMARY KEY CLUSTERED ([ID]);
CREATE NONCLUSTERED INDEX IX_TABLE2 ON #TABLE2([Division],[Platform]);

但是,如果实际的瓶颈是非临时表,那么这可能无法解决您的性能问题。您应该分别运行脚本的SELECT部分。如果他们自己表现良好,请尝试使用这些索引。如果不是,那么您需要与您的DBA交流并找出SELECT运行缓慢的原因。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...