索引如何在SQL中工作以及它提供了哪些好处?
索引列时,表达了在条件表达式中查询索引列的意图,例如相等或范围查询.有了这些信息,存储引擎可以构建一个结构,使这些查询更快,通常将它们安排在树结构中.B树是最常见的,但存在许多不同的结构,例如哈希索引,空间数据的R树索引等.每个结构专门用于某种类型的查找.例如,对于相等条件,哈希索引非常快,例如:
SELECT * FROM example_table WHERE type = "example";
SELECT * FROM example_table WHERE id = X;
Run Code Online (Sandbox Code Playgroud)
对于平等查找,B树也相当快,但它们的主要优势在于它们支持范围查询:
SELECT * FROM example_table WHERE id > 5 AND id < 10
SELECT * FROM example_table WHERE type = "example" and value > 25
Run Code Online (Sandbox Code Playgroud)
但是,当您构建B树索引以了解树以"从左到右"的方式排序时,这非常重要.即,如果你在{type,value}上构建一个B树索引(让我们称之为A),那么你需要在type-column上有一个条件,以便查询能够利用索引.示例索引不能在条件仅依赖于值的查询中使用.此外,如果混合使用相等和范围条件,请确保在索引中首先列出相等列,否则只能部分使用索引.
没有索引的原因是什么?
如果索引的选择性很低,那么您可能无法在表扫描中获得太多收益.比如说你有一个名为性别的字段的索引.然后该索引的选择性将很低,因为对该索引的查找将返回原始表的一半行.你可以在这里阅读关于选择性的非常简单的解释,以及它背后的原因:http://mattfleming.com/node/192
此外,维护索引具有成本.对于每个数据操作,索引可能需要重组.因此,可能需要将索引量保持在对该表的查询执行良好所需的最小值.
索引单个列与索引多个列有什么区别?
再一次,它取决于您发出的查询类型.索引单列性别可能不是一个好主意,因为选择性很低.当选择性高时,这样的指数更有意义.例如,主键上的索引是一个非常好的索引,因为选择性很高(实际上,它高达它.索引中的每个键对应于完全记录),以及具有唯一或高度的列上的索引不同的值(例如slugs,密码哈希和什么不是)也是很好的单列索引.
还有涵盖指数的概念.基本上,索引中的每个叶子都包含一个指向存储行的表的指针(除非索引是聚簇索引.在这种情况下,叶子是记录).因此,对于每个索引命中,查询引擎必须获取相应的表行,从而增加I/O操作的数量.由于I/O非常慢,因此您希望将其保持在最低限度.现在,假设您经常需要查询某些内容,并获取一些额外的列,然后您可以创建覆盖索引,交换存储空间以进行查询性能.示例:让我们找到过去6个月加入的所有用户的名称和电子邮件(假设MySQL):
使用{joined_at}上的索引:
SELECT first_name, last_name, email
FROM users
WHERE joined_at > NOW() - INTERVAL 6 MONTH;
Run Code Online (Sandbox Code Playgroud)
查询说明:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE users ALL test NULL NULL NULL 873 Using where
Run Code Online (Sandbox Code Playgroud)
正如您在type
-column中看到的那样,查询引擎使用了全表扫描,因为索引选择性太低而不值得在此查询中使用(将返回太多结果,因此会进入表中,因此也会花费很多I/O)
使用{joined_at,first_name,last_name,email}上的索引:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE users range test,test2 test2 8 NULL 514 Using where;
Using index
Run Code Online (Sandbox Code Playgroud)
现在,由于索引中提供了完成查询所需的所有信息,因此查询引擎会评估使用索引(包含514行)而不是执行全表扫描要好得多.正如您所看到的,通过使用覆盖索引,我们可以加快查询表的部分选择,即使索引的选择性非常小.