Mur*_*ilo 4 performance sql-server-2014 query-performance
我有一个包含 2,161,524 行的表。我认为计数查询花费的时间太长。
select count(mcon_codigo_pk) from tbMovimentoConta
-- count = 2,161,524
-- time = 9 seconds
select count(1) from tbMovimentoConta
where con_codigo_fk = 1
and mcon_data between '2015-01-05' and '2016-01-06'
-- count = 1,034,729
-- time = 13 seconds
Run Code Online (Sandbox Code Playgroud)
细节:
con_codigo_fk
是bigint
并且具有外键索引(非聚集)mcon_data
是datetime
并且具有索引(非聚集)索引创建脚本
CREATE NONCLUSTERED INDEX [ix_mcon_data] ON [dbo].[tbMovimentoConta]
(
[mcon_data] ASC
)
WITH (
PAD_INDEX = OFF
, STATISTICS_NORECOMPUTE = OFF
, SORT_IN_TEMPDB = OFF
, DROP_EXISTING = OFF
, ONLINE = OFF
, ALLOW_ROW_LOCKS = ON
, ALLOW_PAGE_LOCKS = ON
);
GO
Run Code Online (Sandbox Code Playgroud)
我的电脑有 8GB RAM 和运行 Windows 10 的 Core i7。
我的查询真的需要很长时间还是平均预期时间?如果他们需要很长时间,我该怎么做才能让他们更快?
查询的覆盖索引有两种可能性:
上的复合索引(con_codigo_fk, mcon_data)
。这将涵盖所有类似的查询。如果您添加此索引,您(最有可能)可以安全地删除该索引,(con_codigo_fk)
而将使用新的索引。其他索引(mcon_data)
可以被不同的查询使用,所以我不会删除它。
添加索引的代码:
CREATE INDEX ix__con_codigo_fk__mcon_data -- choose a name
ON dbo.tbMovimentoConta
(con_codigo_fk, mcon_data) ;
Run Code Online (Sandbox Code Playgroud)上的过滤索引(mcon_data) WHERE (con_codigo_fk = 1)
。这当然仅对具有特定值 ( 1
) 的查询有用。
此类索引的用例要少得多,因此它可能对您没有用处。
另一个问题是您使用BETWEEN
的是日期时间类型。这会给您不准确的结果,因为它将包含具有确切日期时间的结果'2016-01-06' 00:00:00'
最好使用包含-不包含的范围:
select count(*)
from tbMovimentoConta
where con_codigo_fk = 1
and mcon_data >= '2015-01-05'
and mcon_data < '2016-01-06' ;
Run Code Online (Sandbox Code Playgroud)
@Aaron Bertrand在博客中对此进行了更详细的解释:和魔鬼有什么BETWEEN
共同点?
另一个问题 - 索引没有试图解决 - 是虽然带有WHERE
条件的查询所需的时间可能是由于计划错误和缺乏适当的索引,第一个查询的时间,整个表计数( 9 秒)听起来有点太多了。(并且添加索引后查询的 1 秒也很高)。
我会在没有更多细节的情况下进行推测,因为解释可能来自许多不同的原因(一般/内存 SQL Server 设置、服务器上的高负载、广泛的聚集索引等),所以我建议您添加有关问题的更多详细信息或发布新问题(CREATE TABLE
如果问题仅针对涉及此表的查询,则使用脚本)。