41

我在 SQL Server 数据库中有一个表,我希望能够尽可能快地搜索和检索数据。我不在乎插入表需要多长时间,我只对获取数据的速度感兴趣。

问题是使用 20 种或更多不同类型的查询访问该表。这使得添加专门为每个查询设计的索引成为一项繁琐的任务。我正在考虑简单地添加一个包含表的所有列的索引。这不是你在“好的”数据库设计中通常会做的事情,所以我假设有一些很好的理由为什么我不应该这样做。

谁能告诉我为什么我不应该这样做?

更新:我忘了提,我也不关心我的数据库的大小。没关系,这意味着我的数据库大小将增长到超过所需的大小

4

8 回答 8

84

首先,SQL Server 中的索引在其索引条目中最多只能有 900 个字节。仅此一项就不可能拥有包含所有列的索引。

最重要的是:这样的索引毫无意义。你想达到什么目的??

考虑一下:如果您在 上有一个索引(LastName, FirstName, Street, City),则该索引将无法用于加快对 的查询

  • FirstName独自的
  • City
  • Street

该索引对于搜索

  • (LastName), 或者
  • (LastName, FirstName), 或者
  • (LastName, FirstName, Street), 或者
  • (LastName, FirstName, Street, City)

但实际上没有别的 - 如果您搜索 justStreet或 just ,当然不会City

索引中列的顺序有很大的不同,查询优化器不能只使用索引中间某处的任何列进行查找。

考虑一下您的电话簿:它可能按姓氏、名字或街道顺序排列。那么该索引是否可以帮助您找到您所在城市的所有“Joe's”?所有住在“大街”的人??不-您可以先按姓氏查找-然后您可以在该组数据中获得更具体的信息。仅仅对所有内容都有一个索引根本无助于加快搜索所有列的速度

如果您希望能够搜索Street- 您需要添加一个单独的索引(Street)(可能还有另一列或两列有意义)。

如果您希望能够通过Occupation其他方式进行搜索 - 您需要另一个特定的索引。

仅仅因为您的列存在于索引中并不意味着这会加快对该列的所有搜索!

主要规则是:使用尽可能少的索引 - 对于一个系统来说,过多的索引可能比没有索引更糟糕......构建你的系统,监控它的性能,并找到那些成本最高的查询 - 然后优化这些,例如通过添加索引。

不要仅仅因为你可以就盲目地索引每一列——这是对糟糕的系统性能的保证——任何索引也需要维护和保养,所以你拥有的索引越多,你的 INSERT、UPDATE 和 DELETE 操作就越会受到影响(获取较慢),因为所有这些索引都需要更新。

于 2011-03-27T08:28:23.277 回答
11

您对索引的工作方式存在根本性的误解。

阅读此解释“多列索引如何工作”。

您可能会遇到的下一个问题是,为什么不为每列创建一个索引——但如果您试图达到最佳选择性能,这也是一个死胡同。

您可能会觉得这是一项乏味的任务,但我会说这是一项需要仔细索引的任务。如本例所示,草率的索引反击。

注意:我坚信正确的索引是有回报的,而且我知道很多人都有与您相同的问题。这就是为什么我要写一本关于它的免费书。上面的链接引用了可能帮助您回答问题的页面。但是,您可能还想从头开始阅读它。

于 2011-03-27T09:46:07.377 回答
2

...如果您添加一个包含所有列的索引,并且查询实际上能够使用该索引,它将按主键的顺序扫描它。这意味着几乎要创下所有记录。平均搜索时间为 O(n/2).. 与访问实际数据库相同。

您需要阅读大量有关索引的内容。

如果您认为表上的索引有点像 C# 中的字典,这可能会有所帮助。

var nameIndex = new Dictionary<String, List<int>>();

这意味着 name 列已编入索引,并将返回主键列表。

var nameOccupationIndex = new Dictionary<String, List<Dictionary<String, List<int>>>>();

这意味着名称列+职业列被索引。现在想象一下索引包含 10 个不同的列,嵌套的深度到目前为止它包含表中的每一行。

请注意,这并不是它的工作原理。但它应该让您了解如果在 C# 中实现索引是如何工作的。你需要做的是基于一个或两个被广泛查询的键创建索引,这样索引比扫描整个表更有用。

于 2011-03-27T08:19:29.273 回答
2

如果这是一个数据仓库类型的操作,其中查询针对 READ 查询进行了高度优化,并且如果您有 20 种剖析数据的方法,例如

WHERE 子句涉及..

 Q1: status, type, customer
 Q2: price, customer, band
 Q3: sale_month, band, type, status
 Q4: customer
 etc

而且你绝对有足够的快速存储空间来燃烧,然后一定要为每一列单独创建一个索引。因此,一个 20 列的表将有 20 个索引,每个单独的列一个。我可能会说忽略位列或低基数列,但是既然我们已经走了这么远,为什么还要麻烦(带着那个警告)。他们只会坐在那里搅动 WRITE 时间,但如果你不关心图片的那一部分,那么我们都很好。

分析您的 20 个查询,如果您有仍然不会更快的热门查询(最热门的查询),请使用 SSMS(按 Ctrl-L)在查询窗口中使用一个查询进行计划。它会告诉你什么索引可以帮助查询——只需创建它;创建它们,充分记住这会再次增加写入成本、备份文件大小、数据库维护时间等。

于 2011-03-27T10:55:31.067 回答
1

我正在考虑简单地添加一个包含表的所有列的索引。

这总是一个坏主意。数据库中的索引不是某种神奇的小精灵。您必须分析您的查询并根据查询的内容和方式 - 附加索引。

它不像“将所有内容添加到索引并打个盹”那么简单

于 2011-03-27T08:18:41.243 回答
0

1)大小,索引本质上是在该列中构建数据的副本,一些易于搜索的结构,如二叉树(我不知道 SQL Server 规范)。2)您提到了速度,索引结构的添加速度较慢。

于 2011-03-27T08:19:36.373 回答
0

我认为提问者在问

'为什么我不能做一个像'这样的索引

create index index_name
on table_name
(
    *
)

这方面的问题已得到解决。

但鉴于听起来他们正在使用 MS sql 服务器。了解您可以在索引中包含非键列是很有用的,因此这些列的值可用于从索引中检索,但不能用作选择标准:

create index index_name
on table_name
(
    foreign_key
)
include (a,b,c,d) -- every column except foreign key

我创建了两个具有一百万行相同的表

我像这样索引表A


create nonclustered index index_name_A
on A
(
    foreign_key -- this is a guid
)

和这样的表B

create nonclustered index index_name_B
on B
(
    foreign_key -- this is a guid
)
include (id,a,b,c,d) -- ( every key except foreign key)

毫不奇怪,表 A 的插入速度稍快一些。

但是当我运行这些查询时

select * from A where foreign_key = @guid
select * from B where foreign_key = @guid

在表 A 上,sql server 甚至没有使用索引,它进行了表扫描,并抱怨缺少索引,包括 id,a,b,c,d

在表 B 上,查询速度提高了 50 倍以上,而 io 少得多

强制 A 上的查询使用索引并没有使其更快

select * from A where foreign_key = @guid
select * from A with (index(index_name_A)) where foreign_key = @guid

于 2019-12-18T04:46:45.780 回答
-1

该索引将与您的表相同(可能按其他顺序排序)。
它不会加快您的查询速度。

于 2011-03-27T08:18:56.373 回答