Sql server 具有大查询的SQL Server性能
大家好,我对一些报告有几个查询,其中每个查询都从35个以上的表中提取数据。每个表都有近10万条记录。例如,所有查询都是Union AllSql server 具有大查询的SQL Server性能,sql-server,sql-server-2008,tsql,sql-server-2008-r2,query-performance,Sql Server,Sql Server 2008,Tsql,Sql Server 2008 R2,Query Performance,大家好,我对一些报告有几个查询,其中每个查询都从35个以上的表中提取数据。每个表都有近10万条记录。例如,所有查询都是Union All ;With CTE AS ( Select col1, col2, col3 FROM Table1 WHERE Some_Condition UNION ALL Select col1, col2, col3 FROM Table2 WHERE Some_Condition UNION ALL Select col1, col2, col3 FROM T
;With CTE
AS
(
Select col1, col2, col3 FROM Table1 WHERE Some_Condition
UNION ALL
Select col1, col2, col3 FROM Table2 WHERE Some_Condition
UNION ALL
Select col1, col2, col3 FROM Table3 WHERE Some_Condition
UNION ALL
Select col1, col2, col3 FROM Table4 WHERE Some_Condition
.
.
. And so on
)
SELECT col1, col2, col3 FROM CTE
ORDER BY col3 DESC
到目前为止,我只在Dev服务器上测试了这个查询,我可以看到获得结果需要时间。所有这35个以上的表都彼此不相关,这是我能想到的在结果集中获得所有所需数据的唯一方法
我不介意在这份报告中读几句脏话。我正在考虑使用查询提示
,并将nolock
或事务隔离级别设置为读取未限制的
这些有帮助吗
编辑
每个表都有5-10位列,每个位列对应一个日期列,每个SELECT语句的条件如下
WHERE BitColumn = 1 AND DateColumn IS NULL
同行建议
过滤索引
CREATE NONCLUSTERED INDEX IX_Table_Column
ON TableName(BitColumn)
WHERE BitColum = 1
包含列的筛选索引
CREATE NONCLUSTERED INDEX fIX_IX_Table_Column
ON TableName(BitColumn)
INCLUDE (DateColumn)
WHERE DateColumn IS NULL
这是最好的方式吗?或者有什么建议吗?您没有给出任何执行的统计数据或示例运行时间,因此无法猜测什么是慢的,什么是真的慢的。结果集中有多少数据?它可能只是检索10万行,因为结果只是花时间。如果10000行的结果集需要5分钟,那么肯定可以看到一些东西。所以,如果您有示例查询,结果中的行数,以及在不同的where条件下执行两次所需的时间,请发布。这将有助于我们比较结果
顺便说一句,不要使用CTE,只需使用常规的内部和外部查询选择。确保临时数据库配置正确。LDF和MDF未默认配置为增加10%。通过一定的尝试和错误,您将知道对于范围查询的验证,日志和临时数据库增加了多少,并在此基础上设置临时数据库的MDF和LDF的初始和增量大小。对于覆盖过滤器索引,包含列应为col1、col2和co3,而不是列日期,除非日期也在选择列表中
原始35个表中的数据更新频率如何?如果每天最多更新一次,或者它们几乎同时更新,那么索引视图可能是一个可行的解决方案。但若原始表一天更新不止一次,或者它们随时都会更新,并且不在同一行中的任何位置,那个么就不要考虑索引视图
如果磁盘空间不是问题,作为最后手段,请尝试在每个表上使用触发器测试性能。创建新表以保存此select查询的最终结果。在检查触发器内部条件的每个表上创建insert/update/delete触发器,如果是,则只将相同的insert/update/delete复制到新表。是的,您需要在新表中使用一列来标识哪些数据来自哪个表。因为Date是一个可以为Null的列,所以您并没有充分利用该列上的索引,因为“大多数情况下,您是在查找Date为Null的位置”。
在新表中,您总是做的唯一查询是Date为NULL的地方,然后甚至不用费心创建该列,只需创建位列和其他col1、col2、col3等。。。如果您给出了查询的真实示例并解释了实际的表,其他详细信息可以在以后解决。查询提示或隔离级别仅在发生任何阻塞时对您有所帮助。
如果您不介意脏读,并且在执行过程中有锁,这可能是一个好主意
关键问题是有多少数据符合您需要使用的Where子句(其中BitColumn=1,DateColumn为NULL)
如果按该值筛选的子集与总行数相比较小,则对两列(BitColn和DateColumn)使用索引,包括select子句中的列,以避免查询计划中的“页面查找”操作
CREATE NONCLUSTERED INDEX IX_[Choose an IndexName]
ON TableName(BitColumn, DateColumn)
INCLUDE (col1, col2, col3)
当然,覆盖过滤索引所需的空间取决于所涉及字段的数据类型以及满足其中BitColumn=1和DateColumn为NULL的行数
之后,我建议使用视图而不是CTE:
CREATE VIEW [Choose a ViewName]
AS
(
Select col1, col2, col3 FROM Table1 WHERE Some_Condition
UNION ALL
Select col1, col2, col3 FROM Table2 WHERE Some_Condition
.
.
.
)
通过这样做,您的查询计划应该看起来像35个小索引扫描,但是如果大多数数据都满足索引的where子句,那么性能将类似于扫描35个源表,解决方案就不值得了
但是你说“每个表都有5-10位的列和相应的日期列…”那么我认为每位列创建一个索引不是一个好主意。
如果需要使用不同的位列和不同的日期列进行筛选,请在表中使用计算列:
ALTER TABLE Table1 ADD ComputedFilterFlag AS
CAST(
CASE WHEN BitColum1 = 1 AND DateColumn1 IS NULL THEN 1 ELSE 0 END +
CASE WHEN BitColum2 = 1 AND DateColumn2 IS NULL THEN 2 ELSE 0 END +
CASE WHEN BitColum3 = 1 AND DateColumn3 IS NULL THEN 4 ELSE 0 END
AS tinyint)
我建议您对conditionX使用值2^(X-1)(BitColumnX=1,DateColumnX不为空)。它将允许您使用该标准的任意组合进行过滤。
通过使用值3,您可以找到完成以下条件的所有行:Bit1,Date1和Bit2,Date2条件。任何条件组合都有其相应的ComputedFilterFlag值,因为ComputedFilterFlag充当条件的位图。
如果您拥有少于8个不同的筛选器,则应使用tinyint以节省索引中的空间并减少所需的IO操作
然后在计算的FilterFlag列上使用索引:
CREATE NONCLUSTERED INDEX IX_[Choose an IndexName]
ON TableName(ComputedFilterFlag)
INCLUDE (col1, col2, col3)
并创建视图:
CREATE VIEW [Choose a ViewName]
AS
(
Select col1, col2, col3 FROM Table1 WHERE ComputedFilterFlag IN [Choose the Target Filter Value set]--(1, 3, 5, 7)
UNION ALL
Select col1, col2, col3 FROM Table2 WHERE ComputedFilterFlag IN [Choose the Target Filter Value set]--(1, 3, 5, 7)
.
.
.
)
通过这样做,您的索引覆盖了所有条件,您的查询计划应该看起来像35个小索引
但这是一个棘手的解决方案,可能是在表架构中进行重构可以产生更简单、更快的结果。可以做很多事情使其更快。
如果我假设你需要进行这些联合,那么你可以