我对MySQL索引的工作方式非常感兴趣,更具体地说,他们如何在不扫描整个表的情况下返回所请求的数据?
我知道,这是偏离主题的,但如果有人可以向我详细解释这一点,我将非常非常感谢.
Pis*_*3.0 498
基本上,表上的索引就像书中的索引(名称来自的位置):
假设你有一本关于数据库的书,你想找一些关于存储的信息.没有索引(假设没有其他帮助,例如目录),您必须逐个浏览页面,直到找到主题(即a full table scan
).另一方面,索引有一个关键字列表,所以你可以参考索引,看看storage
第113-120,231和354页上提到的那个.然后你可以直接翻到这些页面,而无需搜索(这是一个搜索索引,有点快).
当然,索引的有用性取决于很多东西 - 一些例子,使用上面的明喻:
cla*_*ete 252
您必须知道的第一件事是索引是一种避免扫描整个表以获得您正在寻找的结果的方法.
存在不同类型的索引,它们在存储层中实现,因此它们之间没有标准,它们也依赖于您正在使用的存储引擎.
对于InnoDB,最常见的索引类型是基于B + Tree的索引,它以排序顺序存储元素.此外,您不必访问实际表来获取索引值,这使您的查询返回更快.
关于此索引类型的"问题"是您必须查询最左边的值才能使用索引.因此,如果您的索引有两列,例如last_name和first_name,那么查询这些字段的顺序非常重要.
因此,如下表所示:
CREATE TABLE person (
last_name VARCHAR(50) NOT NULL,
first_name VARCHAR(50) NOT NULL,
INDEX (last_name, first_name)
);
Run Code Online (Sandbox Code Playgroud)
此查询将利用索引:
SELECT last_name, first_name FROM person
WHERE last_name = "John" AND first_name LIKE "J%"
Run Code Online (Sandbox Code Playgroud)
但是下面的那个不会
SELECT last_name, first_name FROM person WHERE first_name = "Constantine"
Run Code Online (Sandbox Code Playgroud)
因为您first_name
首先查询列,而不是索引中最左侧的列.
最后一个例子更糟糕:
SELECT last_name, first_name FROM person WHERE first_name LIKE "%Constantine"
Run Code Online (Sandbox Code Playgroud)
因为现在,您正在比较索引中最右边字段的最右边部分.
这是一种不同的索引类型,遗憾的是,只有内存后端支持.这是快如闪电,但仅适用于全查找有用的,这意味着你不能使用它像操作>
,<
或LIKE
.
由于它仅适用于内存后端,因此您可能不会经常使用它.我现在能想到的主要情况是你在内存中创建一个临时表,其中包含来自另一个select的一组结果,并使用哈希索引在此临时表中执行许多其他选择.
如果你有一个大VARCHAR
字段,你可以在使用B-Tree时"模拟"哈希索引的使用,通过创建另一个列并在其上保存大值的哈希值.假设你在一个字段中存储一个url,值非常大.您还可以创建一个调用的整数字段,url_hash
并CRC32
在插入时使用哈希函数或任何其他哈希函数来对哈希进行哈希处理.然后,当您需要查询此值时,您可以执行以下操作:
SELECT url FROM url_table WHERE url_hash=CRC32("http://gnu.org");
Run Code Online (Sandbox Code Playgroud)
上面这个例子的问题是,由于CRC32
函数生成一个非常小的哈希值,你最终会在哈希值中产生大量的冲突.如果您需要确切的值,可以通过执行以下操作来解决此问题:
SELECT url FROM url_table
WHERE url_hash=CRC32("http://gnu.org") AND url="http://gnu.org";
Run Code Online (Sandbox Code Playgroud)
即使碰撞数很高,它仍然值得散列,因为你只会对重复的散列执行第二次比较(字符串1).
不幸的是,使用这种技术,您仍然需要点击表格来比较该url
字段.
您每次想要谈论优化时可能会考虑的一些事实:
整数比较比字符串比较快.它可以通过示例来说明哈希索引的仿真InnoDB
.
也许,在一个过程中添加额外的步骤会使它更快,而不是更慢.可以通过以下事实来说明:您可以SELECT
通过将其拆分为两个步骤来优化a ,使第一个在新创建的内存表中存储值,然后在第二个表上执行较重的查询.
MySQL有其它的指标太多,但我认为B +树一个是有史以来最常用和散列是认识个好东西,但你可以找到在其他的MySQL文档.
我强烈建议你阅读"高性能MySQL"一书,上面的答案肯定是基于它关于索引的章节.
Jos*_*hua 38
基本上,索引是按顺序排序的所有键的映射.按顺序列表,然后它可以执行以下操作,而不是检查每个键:
1:进入列表中间 - 是高还是低于我正在寻找的?
2:如果更高,则进入中间和底部之间的中间位置,如果是低位,中位和顶部
3:更高还是更低?再次跳到中间点等
使用该逻辑,您可以在大约7个步骤中找到排序列表中的元素,而不是检查每个项目.
显然有复杂性,但这给了你基本的想法.
在MySQL InnoDB中,有两种类型的索引。
主键称为聚集索引。索引关键字与真实记录数据一起存储在B+Tree叶子节点中。
辅助键是非聚集索引。这些索引仅在 B+Tree 叶子节点中存储主键的关键字以及它们自己的索引关键字。所以从二级索引查找时,会先找到其主键索引关键字,然后扫描主键B+Tree,找到真正的数据记录。与主索引搜索相比,这将使辅助索引速度变慢。但是,如果select
列都在二级索引中,则无需再次查找主索引B+Tree。这称为覆盖索引。