我在SQL Server数据库中有一个表,我希望能够尽快搜索和检索数据。我不关心插入表格需要多长时间,我只对获取数据的速度感兴趣。
问题是使用20种或更多不同类型的查询访问该表。这使得添加专为每个查询设计的索引变得繁琐。我正在考虑只是添加一个包含表的所有列的索引。这不是你在“好”的数据库设计中通常会做的事情,所以我假设有一些很好的理由我不应该这样做。
谁能告诉我为什么不这样做?
更新:我忘了提,我也不关心我的数据库的大小。没关系,这意味着我的数据库大小将超过
所需的大小答案 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)
答案 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)
该索引与您的表格相同(可能按其他顺序排序) 它不会加快您的查询速度。