在SQL中基于群集和非群集索引优化查询?

时间:2014-09-12 19:16:39

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

我最近一直在阅读clustered indexnon-clustered index的工作原理。我用简单的术语理解(如果错误,请纠正我):

支持clusterednon-clustered index的数据结构为B-Tree

Clustered Index:根据索引列(或键)对数据进行物理排序。每clustered Index只能有一个table。如果在创建表格期间未指定indexSQL服务器将自动在clustered Index上创建primary key column

Q1 :由于数据是根据索引进行物理排序的,因此此处不需要额外的空间。它是否正确?那么当我删除我创建的索引时会发生什么?

Non-clustered Index:在non-clustered indexes中,树的leaf-node包含列值和指向数据库中实际行的指针(行定位器)。这里存在将non-clustered index table物理存储在磁盘上所需的额外空间。但是,一个不受non-clustered Indexes.

的数量限制

Q2 :这是否意味着对非聚集索引列的查询不会导致排序数据?

Q3 :此处有一个额外的查找,用于使用叶节点处的指针定位实际的行数据。与聚簇索引相比,这会产生多大的性能差异?

锻炼; Tibial:

考虑一个员工表:

CREATE TABLE Employee
(
PersonID int PRIMARY KEY,
Name varchar(255),
age int,
salary int
); 

现在我创建了一个员工表(创建了员工的默认聚集索引)。

此表上的两个常见查询仅发生在年龄和工资列上。为简单起见, 假设表格不经常更新

例如:

select * from employee where age > XXX;

select * from employee where salary > XXXX and salary < YYYY;

Q4 :构建索引的最佳方法是什么,以便这两列上的查询具有相似的性能。如果我对年龄段上的年龄查询的聚簇索引会更快,但是在工资列上会更慢。

Q5 :在相关的说明中,我反复看到应该在具有唯一约束的列上创建索引(聚簇和非聚簇)。这是为什么?未能做到这一点会发生什么?

非常感谢你 我读过的帖子在这里:

http://javarevisited.blogspot.com/2013/08/difference-between-clustered-index-and-nonclustered-index-sql-server-database.html

http://msdn.microsoft.com/en-us/library/ms190457.aspx

Clustered vs Non-Clustered

What do Clustered and Non clustered index actually mean?

What are the differences between a clustered and a non-clustered index?

How does database indexing work?

2 个答案:

答案 0 :(得分:5)

我不知道Microsoft SQL Server的内部,但我可以回答你为你的问题标记的MySQL。其他实现的细节可能会有所不同。

Q1。是的,聚集索引不需要额外的空间。

如果删除聚集索引会发生什么? MySQL的InnoDB引擎始终使用主键(或第一个非空唯一键)作为聚簇索引。如果您定义没有主键的表,或者删除现有表的主键InnoDB generates an internal artificial key for the clustered index。此内部键没有逻辑列来引用它。

Q2。不保证使用非聚集索引的查询返回的行顺序。实际上,它是访问行的顺序。如果您需要按特定顺序返回行,则应在查询中使用ORDER BY。如果优化器可以推断出您所需的顺序与访问行的顺序(索引顺序,无论是通过聚簇索引还是非聚集索引)相同,那么它可以跳过排序步骤。

Q3。 InnoDB非聚集索引没有指向索引叶子上相应行的指针,它具有主键的。因此,非聚集索引中的查找实际上是两个B树搜索,第一个是查找非聚集索引的叶子,然后是聚簇索引中的第二个搜索。

这是单个B树搜索(或多或少)的两倍,因此InnoDB有一个名为Adaptive Hash Index的额外功能。经常搜索的值会缓存在AHI中,并且下次查询搜索缓存值时,它可以执行O(1)查找。在AHI缓存中,它找到一个直接指向聚簇索引的叶子的指针,因此它在一部分时间内消除了两个 B树搜索。

这可以提高总体性能取决于您搜索之前搜索过的相同值的频率。根据我的经验,哈希搜索与非哈希搜索的比率通常约为1:2。

Q4。构建索引以提供您需要优化的查询。通常,聚簇索引是主键或唯一键,至少在InnoDB的情况下,这是必需的。 agesalary都不可能是唯一的。

您可能会喜欢我的演示文稿How to Design Indexes, Really

Q5。当您声明唯一约束时,InnoDB会自动创建索引。如果没有为其存在索引,则不能拥有约束。如果您没有索引,那么在插入值时引擎如何确保唯一性?它需要在整个表中搜索该列中的重复值。该索引有助于使独特的检查更加有效。

答案 1 :(得分:3)

对于SQL Server

Q1 只有聚集索引不是唯一的,才需要额外的空间。 SQL Server将在内部向非唯一聚簇索引添加一个4字节的uniquifier。这是因为它使用群集密钥作为非聚集索引中的rowid。

Q2 可以按顺序读取非聚集索引。这可能有助于您指定订单的查询。它也可能使合并连接具有吸引力。它还有助于范围查询(x&lt; col和y&gt; col)。

Q3 SQL Server执行额外的&#34;书签查找&#34;使用非聚集索引时。但是,只有当它需要一个不在索引中的列时。另请注意,您可以在索引的叶级别中添加include个额外列。如果可以在没有附加查找的情况下使用索引,则将其称为覆盖索引。

如果需要书签查找,则不会占用很高比例的行,直到扫描整个聚簇索引更快。级别取决于行大小,密钥大小等。但行的5%是典型的截止。

Q4 如果您的应用中最重要的事情是尽可能快地完成这两个查询,您可以在这两个查询上创建覆盖索引:

create index IX_1 on employee (age) include (name, salary);
create index IX_2 on employee (salary) include (name, age);

请注意,您不必专门包含群集密钥,因为非群集索引将其作为行指针。

Q5 由于uniquifier,这对于群集密钥比非群集密钥更重要。但真正的问题是索引是否对您的查询具有选择性。想象一下bit值的索引。除非数据分布非常偏斜,否则这样的索引不可能用于任何事情。


有关uniquifier的更多信息。想象一下你和一个关于年龄的非唯一聚集索引,以及一个关于薪水的非聚集索引。假设您有以下行:

age | salary | uniqifier
20  | 1000   | 1
20  | 2000   | 2

然后工资指数会找到像这样的行

1000 -> 20, 1
2000 -> 20, 2

假设您运行了查询select * from employee where salary = 1000,并且优化器选择使用工资索引。然后它会从索引查找中找到对(20,1),然后在主数据中查找该值。