我应该在SQL Server的此表上创建哪些索引?

时间:2018-07-05 14:10:35

标签: sql sql-server database indexing

我有一个具有以下定义的表:

CREATE TABLE [dbo].[Transactions]
(
    [ID] [varchar](18) NOT NULL,
    [TIME_STAMP] [datetime] NOT NULL,
    [AMT] [decimal](18, 4) NOT NULL,
    [CID] [varchar](90) NOT NULL,
    [DEPARTMENT] [varchar](4) NULL,
    [SOURCE] [varchar](14) NULL,
    PRIMARY KEY NONCLUSTERED 
    (
        [ID] ASC
    )
    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

该表中有7500万行。不知何故,它占用了20 GB的磁盘空间!

以下2个查询...

SELECT 
    SUM(AMT) 
FROM 
    Transactions
WHERE 
    TIME_STAMP >= '2017-11-11 00:00:00' AND 
    TIME_STAMP < '2017-11-12 00:00:00'


SELECT 
    COUNT(DISTINCT(CID))
FROM 
    Transactions
WHERE 
    TIME_STAMP >= '2017-11-11 00:00:00' AND 
    TIME_STAMP < '2017-11-12 00:00:00'

...每次运行大约需要2分钟!

顺便说一句,该表具有无法删除的“聚集的列存储索引”,因为上次尝试删除它时,由于磁盘空间不足,DROP失败。缩小数据库后,存储数据的驱动器有28 GB的可用空间(50 GB可用空间)。

请告知我该怎么做,需要创建哪些索引以及使用哪些设置来优化这些查询和WHY的性能,以便我和其他人可以理解和学习。

此外,如果我还需要在某些WHERE子句中指定DEPARTMENT和SOURCE,该怎么办?这些列只有几个不同的值。

谢谢!

4 个答案:

答案 0 :(得分:1)

我认为一个索引就足够了:

create index idx_transactions_timestamp_cid_amt on transactions(timestamp, cid, amt);

这涵盖了第一个查询。索引中的cid与查询中索引的使用无关。索引将根据日期进行扫描。您可以选择“包含” amt,而不是将其作为单独的键。

答案 1 :(得分:0)

Time_Stamp上创建包含AMTCID的索引应该优化您问题中的查询。

“为什么”是一个广泛的主题,不太适合堆栈溢出的答案。阅读有关SQL Server索引的教程和博客。

编辑评论评论:

您在WHERE子句中进行过滤的列应该是索引本身的一部分(即使它们只有几个不同的值),您刚刚在SELECT列表中返回的列也应该是索引的INCLUDES子句的一部分

答案 2 :(得分:0)

一般的经验法则是为where子句中的列建立索引,而任何连接谓词都是粗略的指南,而不仅仅是狂加应用SSMS的索引提示,它们常常在说谎,因为它们会变得更好

如果您将索引放在TIME_STAMP上,并将该列包括在选择列中,作为包含列或键,则它们对两个查询都将产生积极影响。

例如

CREATE INDEX IX_TEST1 on Transactions (TIME_STAMP) INCLUDE (AMT)
CREATE INDEX IX_TEST1 on Transactions (TIME_STAMP) INCLUDE (CID)

缺点是这些是date和varchar字段,因此索引将变得很大

答案 3 :(得分:0)

您需要在表上创建聚簇索引(通常是主键,该主键可以由一个或多个合并为唯一值的列组成。聚簇索引不必是唯一的,但主键必须是。会猜出id是主键的合适候选者,然后我根据time_stamp创建一个索引,并包含CID和Amt。

您希望查询使用查找(这意味着SQL Server仅读取相关的行)而不是扫描(其中SQL Server读取整个表)。

同样,我们看不到数据,但这是我的建议:

alter table [dbo].[Transactions] add constraint PK_transactions_id primary key ( id);
create index ix_transactions_time_stamp_amt on transactions(timestamp) include (cid,amt);