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

zpqajqem  于 2022-11-28  发布在  其他
关注(0)|答案(9)|浏览(186)

我在SQL Server数据库中有一个表,我希望能够尽可能快地从该表中搜索和检索数据。我不关心插入到表中需要多长时间,我只关心获取数据的速度。
问题是表被20个或更多不同类型的查询访问。这使得为每个查询添加一个专门设计的索引是一项乏味的任务。我正在考虑简单地添加一个包含表的所有列的索引。这不是你通常在“好的”数据库设计中会做的事情,所以我假设有一些很好的理由我不应该这样做。
谁能告诉我为什么我不该这么做?
更新:我忘了说,我也不关心我的数据库的大小。这意味着我的数据库大小会比它需要的大

q5lcpyga

q5lcpyga1#

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

x6492ojm

x6492ojm2#

我在这里只看到冗长而复杂的答案,所以我想我应该给予出尽可能简单的答案。
不能将整个表或其所有列添加到索引中,因为这样做只是复制表。
简单地说,索引就是另一个表,其中的选定数据按照您通常希望查询的顺序排序,索引是指向磁盘上其余数据所在行的指针。
因此,存在一个间接级别。(假设索引没有分段,则在磁盘和RAM上都是如此),这样可以更快地只查询索引中定义的列,而不必扫描磁盘来获取其余列,因为索引包含对磁盘上每行剩余数据所在位置的引用。

68de4m5k

68de4m5k3#

该索引将与您的表完全相同(可能以另一种顺序排序)。
它不会加快查询速度。

daupos2t

daupos2t4#

首先,SQL Server中的索引在其索引项中最多只能有900个字节,这使得不可能有一个包含所有列的索引。
最重要的是:这样的指数完全没有意义,你想达到什么目的?
请考虑以下内容:如果您在(LastName, FirstName, Street, City)上有一个索引,则该索引将不能用于加快对

  • FirstName单独给药
  • City
  • Street

该索引对于搜索

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

但真的没有别的-当然不是如果你只搜索Street或只搜索City
索引中列的顺序会产生很大的差异,查询优化器不能只使用索引中间的任何列进行查找。
以您的电话簿为例:它可能是按姓氏、名字排序的,也可能是按街道排序的。那么,索引是否有助于您查找城市中所有的“Joe 's”?是否有助于查找居住在“Main Street”上的所有人??不,您可以先按姓氏查找,然后在该数据集中查找更具体的内容。仅仅对所有内容建立索引并不能帮助您加快搜索所有列的速度****。
如果您希望能够按Street进行搜索-您需要在(Street)上添加一个单独的索引(可能还有另外一两个有意义的列)。
如果你想能够搜索Occupation或其他什么-你需要另一个特定的索引。
仅仅因为您的列存在于索引中并不意味着可以加快对该列的所有搜索!
主要的规则是:使用尽可能少的索引-对于一个系统来说,太多的索引甚至比没有索引更糟糕....构建您的系统,监控其性能,并找到那些开销最大的查询-然后优化这些查询,例如通过添加索引。
不要盲目地为每一列建立索引--这是对糟糕的系统性能的保证--任何索引都需要维护和保养,所以索引越多,INSERT、UPDATE和DELETE操作就越困难(变得更慢),因为所有这些索引都需要更新。

svmlkihl

svmlkihl5#

您对索引的工作原理有一个根本性的误解。
阅读此说明“how multi-column indexes work“。
下一个问题可能是为什么不创建one index per column--但如果您试图达到顶级性能,这也是一条死胡同。
你可能会觉得这是一个“乏味”的任务,但我会说这是一个“必需”的任务来仔细索引。
注意:我坚信正确的索引是值得的,我知道很多人都有和你一样的问题。这就是为什么我写了一本关于它的免费书。上面的链接指向可能帮助你回答问题的页面。但是,你可能也想从beginning上读到它。

piok6c0g

piok6c0g6#

如果你添加了一个包含所有列的索引,并且一个查询实际上可以使用这个索引,它会按照主键的顺序扫描它。这意味着几乎命中了每一条记录。平均搜索时间将是O(n/2)。
你需要读很多关于索引的书。
如果您将数据表上的索引视为有点像C#中的Dictionary,可能会有所帮助。

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

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

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

这意味着name列+ occupation列被索引。现在想象一下索引包含10个不同的列,嵌套到包含表中每一行的深度。
请注意,这并不是它的工作方式。但它应该给予您了解如果在C#中实现索引,索引将如何工作。您需要做的是基于一个或两个广泛查询的键创建索引,这样索引比扫描整个表更有用。

niknxzdl

niknxzdl7#

如果这是一个数据仓库类型的操作,其中查询针对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)在查询窗口中计划一个查询。它会告诉你什么索引可以帮助查询-只需创建它;创建所有备份文件,要完全记住这会再次增加写入成本、备份文件大小、数据库维护时间等。

5kgi1eie

5kgi1eie8#

我想提问者是在问

  • '为什么我不能创建索引'*:
create index index_name
on table_name
(
    *
)

这方面的问题已经得到解决。
但是,如果听起来像是在使用MS sql server,那么了解一下可以在索引中包含非键列,以便可以从索引中检索这些列的值,但不能将其用作选择标准是很有用的:

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
pkbketx9

pkbketx99#

我考虑只添加一个包含表的所有列的索引。
这总是一个坏主意。数据库中的索引不是某种神奇的精灵灰尘。你必须分析你的查询,并根据查询的内容和方式来添加索引。
这并不像“把所有东西都加到索引里,然后打个盹”那么简单

相关问题