为什么我不能简单地添加包含所有列的索引?

时间:2011-03-27 08:14:16

标签: sql sql-server indexing non-clustered-index

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

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

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

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

所需的大小

8 个答案:

答案 0 :(得分:70)

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

最重要的是:这样的索引完全没有意义。你想要实现什么?

请考虑一下:如果您在(LastName, FirstName, Street, City)上有索引,该索引将能够用于加速查询

  • FirstName
  • City
  • Street

该索引对于

上的搜索非常有用
  • (LastName)
  • (LastName, FirstName)
  • (LastName, FirstName, Street)
  • (LastName, FirstName, Street, City)

但实际上没有别的 - 如果你只搜索Street或只搜索City,肯定不会!

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

考虑一下你的电话簿:它的订单可能是LastName,FirstName,也许是Street。那么索引是否可以帮助您找到您所在城市的所有“Joe's”?所有人都住在“主街”?不 - 您可以先通过LastName查找 - 然后在该组数据中获得更具体的信息。只对所有内容编制索引并没有帮助加快搜索所有列。

如果您希望能够按Street进行搜索,则需要在(Street)上添加一个单独的索引(可能还有一两个有意义的列)。

如果您希望能够按Occupation或其他任何方式进行搜索,则需要另外一个特定索引。

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

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

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

答案 1 :(得分:8)

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

阅读此解释“how multi-column indexes work”。

您可能遇到的下一个问题是为什么不创建one index per column - 但如果您尝试达到最佳选择性能,那么这也是一个死胡同。

您可能会觉得这是一个繁琐的任务,但我会说这是必需的任务,要仔细索引。如this example中那样,马虎索引回击。

注意:我坚信正确的索引会得到回报,我知道很多人都有同样的问题。这就是为什么我正在写一本关于它的免费书。上面的链接指的是可能帮助您回答问题的页面。但是,您可能还想从beginning中读取它。

答案 2 :(得分:2)

  

我正在考虑只添加一个包含表格所有列的索引。

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

这并不像“将所有内容添加到索引并小睡一样简单”

答案 3 :(得分:2)

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

您需要阅读关于索引的

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

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

这意味着名称列已编制索引,并将返回主键列表。

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

这意味着名称列+占用列已编入索引。现在假设索引包含10个不同的列,嵌套到目前为止很深,它包含表中的每一行。

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

答案 4 :(得分: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)在查询窗口中使用一个查询进行规划。它会告诉你哪些索引可以帮助查询 - 只需创建它;创建它们,完全记住这会再次增加写入成本,备份文件大小,数据库维护时间等。

答案 5 :(得分:0)

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

答案 6 :(得分: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

答案 7 :(得分:-1)

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