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不伤写作时间尽可能多的将是在创建一个非聚集索引Source和ShortDate.
我喜欢这样,索引架构:
CREATE NONCLUSTERED INDEX [Source&Time]
ON [dbo].[reports]([Source] ASC, [ShortDate] ASC)
Run Code Online (Sandbox Code Playgroud)
现在我们正处于让我彻底迷失的棘手部分,上面的索引有时会起作用,有时候一半是有效的,有时根本不起作用....
(不确定它是否重要但目前90%的数据库行具有相同的Source,尽管这不会长久保持这样)
通过下面的查询,根本不使用索引,我正在使用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)与此查询,该指数完全不使用,但我越来越从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 + ShortDate和ShortDate + Source
但由于某种原因,它必须包含所有列...(这将极大地影响对该表的写入?)
非常感谢阅读,我的目标是了解为什么会发生这种事情以及我应该做些什么(不仅仅是解决方案,因为我还需要将其应用于其他项目).
干杯:)
mar*_*c_s 11
SQL Server中的索引是长期经验(以及许多小时的挫折)的部分专有技术,也是部分黑魔法.不要过多地打败自己 - 这就像SO这样的地方是理想的 - 很多大脑,经过多个小时的优化,你可以利用的经验.
我读到索引应该按查询的顺序进行?
如果你读到这个 - 它绝对不是 - 列的顺序是相关的 - 但是以不同的方式:只有在你指定n个最左边的列时,才会考虑复合索引(由多个列组成)查询中的索引定义.
经典示例:索引为(city,lastname,firstname)的电话簿.可以使用这样的索引:
WHERE子句中的所有三列city和的查询中lastname(在"底特律"中找到所有"米勒")但是如果你只想搜索..... 那就永远不会被使用firstname..... 这就是你需要注意的复合索引的诀窍.但是如果你总是使用索引中的所有列,它们的排序通常并不真正相关 - 查询优化器会为你处理这个.
而对于包含的列 -这些被存储仅在非聚集索引的叶级-他们是不是索引的搜索结构的一部分,你不能为你的那些包含列指定过滤器值WHERE子句.
这些包含列的主要好处是:如果您在非聚集索引中搜索,最后,您实际上找到了您正在寻找的值 - 那时您有什么可用的?非聚集索引将列存储在非聚集索引定义(ShortDate和Source)中,它将存储聚类键(如果你有一个 - 你应该!) - 但没有别的.
因此,在这种情况下,一旦找到匹配项,并且您的查询需要该表中的所有内容,SQL Server必须执行所谓的密钥查找(通常也称为书签查找),其中它采用聚簇密钥,然后对聚集索引执行Seek操作,以获取包含您正在查找的所有值的实际数据页.
如果已在索引中包含列,则包含非聚集索引的叶级页面
INCLUDE语句中定义的所有其他列如果这些列"覆盖"您的查询,例如提供查询所需的所有值,则SQL Server在找到您在非聚簇索引中搜索的值后完成 - 它可以从该叶级获取所需的所有值非聚簇索引的页面,它不需要对聚类索引执行另一个(昂贵的)键查找以获取实际值.
正因为如此,试图总是明确地指定只有那些你列确实需要在你的SELECT可能是有益的-在这种情况下,你也许可以创造一个高效的覆盖索引,它为您的所有值SELECT-始终用SELECT *品牌真的很难或旁边不可能......