日期范围查询的SQL索引

Ben*_*Ben 9 sql database indexing database-performance sql-server-2014

几天来,我一直在努力提高我的数据库的性能,并且有些问题我仍然对SQL Server数据库中的索引感到困惑.

我会尽量提供尽可能丰富的信息.

我的数据库目前包含大约10万行并且将继续增长,因此我正在努力寻找一种方法来使其更快地工作.

我也写信给这张桌子,所以如果你的建议会大大缩短写作时间,请告诉我.

总体目标是选择具有日期范围内特定名称的所有行.

通常情况下,选择超过3,000行lol ...

表模式:

CREATE TABLE [dbo].[reports]
(
    [id] [int] IDENTITY(1,1) NOT NULL,
    [IsDuplicate] [bit] NOT NULL,
    [IsNotValid] [bit] NOT NULL,
    [Time] [datetime] NOT NULL,
    [ShortDate] [date] NOT NULL,
    [Source] [nvarchar](350) NULL,
    [Email] [nvarchar](350) NULL,

    CONSTRAINT [PK_dbo.reports] 
        PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)

这是我正在使用的SQL查询:

SELECT * 
FROM [db].[dbo].[reports]
WHERE Source = 'name1' 
  AND ShortDate BETWEEN '2017-10-13' AND '2017-10-15'
Run Code Online (Sandbox Code Playgroud)

我的理解,我的最好的方法,以提高efficency不伤写作时间尽可能多的将是在创建一个非聚集索引SourceShortDate.

我喜欢这样,索引架构:

CREATE NONCLUSTERED INDEX [Source&Time] 
ON [dbo].[reports]([Source] ASC, [ShortDate] ASC)
Run Code Online (Sandbox Code Playgroud)

现在我们正处于让我彻底迷失的棘手部分,上面的索引有时会起作用,有时候一半是有效的,有时根本不起作用....

(不确定它是否重要但目前90%的数据库行具有相同的Source,尽管这不会长久保持这样)

  1. 通过下面的查询,根本不使用索引,我正在使用SQL Server 2014,并且在执行计划中它说它只使用聚簇索引扫描:

    SELECT * 
    FROM [db].[dbo].[reports]
    WHERE Source = 'name1' 
      AND ShortDate BETWEEN '2017-10-10' AND '2017-10-15'
    
    Run Code Online (Sandbox Code Playgroud)
  2. 与此查询,该指数完全不使用,但我越来越从SQL Server的一个建议,创建日期第一和第二源的指标......我读该指数应该由订单查询进行是什么?它还说要包括我选择的所有列,这是必须的吗?...再次我读到我应该只在索引中包含我正在搜索的列.

    SELECT * 
    FROM [db].[dbo].[reports]
    WHERE Source = 'name1' 
      AND ShortDate = '2017-10-13'
    
    Run Code Online (Sandbox Code Playgroud)

    SQL Server索引建议 -

    /* The Query Processor estimates that implementing the following 
       index could improve the query cost by 86.2728%. */
    
    /*
    USE [db]
    GO
    
    CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
    ON [dbo].[reports] ([ShortDate], [Source])
    INCLUDE ([id], [IsDuplicate], [IsNotValid], [Time], [Email])
    GO
    */
    
    Run Code Online (Sandbox Code Playgroud)

现在我尝试使用SQL Server建议我制作的索引并且它可以工作,看起来它使用上面的查询使用100%的非聚集索引.

我试图使用这个索引,但删除包含的列,它不起作用......似乎我必须在索引中包括我正在选择的所有列?

顺便说一句,如果我包含所有列,它在使用我制作的索引时也有效.

总结:好像索引的顺序并不重要,因为它的工作都在创建时Source + ShortDateShortDate + Source

但由于某种原因,它必须包含所有列...(这将极大地影响对该表的写入?)

非常感谢阅读,我的目标是了解为什么会发生这种事情以及我应该做些什么(不仅仅是解决方案,因为我还需要将其应用于其他项目).

干杯:)

mar*_*c_s 11

SQL Server中的索引是长期经验(以及许多小时的挫折)的部分专有技术,也是部分黑魔法.不要过多地打败自己 - 这就像SO这样的地方是理想的 - 很多大脑,经过多个小时的优化,你可以利用的经验.

我读到索引应该按查询的顺序进行?

如果你读到这个 ​​- 它绝对不是 - 列的顺序相关的 - 但是以不同的方式:只有在你指定n个最左边的列时,才会考虑复合索引(由多个列组成)查询中的索引定义.

经典示例:索引为(city,lastname,firstname)的电话簿.可以使用这样的索引:

  • 在查询中指定其WHERE子句中的所有三列
  • 在使用city和的查询中lastname(在"底特律"中找到所有"米勒")
  • 或者仅在按城市过滤的查询中

但是如果你只想搜索..... 那就永远不会被使用firstname..... 这就是你需要注意的复合索引的诀窍.但是如果你总是使用索引中的所有列,它们的排序通常并不真正相关 - 查询优化器会为你处理这个.


而对于包含的列 -这些被存储在非聚集索引的叶级-他们是不是索引的搜索结构的一部分,你不能为你的那些包含列指定过滤器值WHERE子句.

这些包含列的主要好处是:如果您在非聚集索引中搜索,最后,您实际上找到了您正在寻找的值 - 那时您有什么可用的?非聚集索引将列存储在非聚集索引定义(ShortDateSource)中,它将存储聚类键(如果你有一个 - 你应该!) - 但没有别的.

因此,在这种情况下,一旦找到匹配项,并且您的查询需要该表中的所有内容,SQL Server必须执行所谓的密钥查找(通常也称为书签查找),其中它采用聚簇密钥,然后对聚集索引执行Seek操作,以获取包含您正在查找的所有值的实际数据页.

如果已在索引中包含列,则包含非聚集索引的叶级页面

  • 非聚集索引中定义的列
  • 群集键列
  • INCLUDE语句中定义的所有其他列

如果这些列"覆盖"您的查询,例如提供查询所需的所有值,则SQL Server在找到您在非聚簇索引中搜索的值后完成 - 它可以从该叶级获取所需的所有值非聚簇索引的页面,它不需要对聚类索引执行另一个(昂贵的)键查找以获取实际值.

正因为如此,试图总是明确地指定只有那些你列确实需要在你的SELECT可能是有益的-在这种情况下,你也许可以创造一个高效的覆盖索引,它为您的所有值SELECT-始终用SELECT *品牌真的很难或旁边不可能......