MySQL索引如何工作?
我对MySQL索引的工作方式非常感兴趣,更具体地说,他们如何在不扫描整个表的情况下返回请求的数据?
我知道,这是无关紧要的,但是如果有人能够详细解释我的话,我会非常非常感激。
基本上,表格上的索引就像书中的索引(这就是名字的来源):
比方说,你有一本关于数据库的书,你想find一些关于存储的信息。 如果没有索引(假设没有其他帮助,例如目录),则必须逐页浏览这些页面,直到find主题(即full table scan
)为止。 另一方面,一个索引有一个关键字列表,所以你可以参考索引,看到storage
在第113-120,231和354页。然后你可以直接翻到这些页面,而不用search(这是一个search一个索引,有点更快)。
当然,这个指数有多有用,取决于很多东西 – 几个例子,使用上面的比喻:
- 如果你有一本关于数据库的书,并将“数据库”这个词编入索引,你会发现在第1-59,61-290页和第292-400页中提到过。在这种情况下,索引没有太大的帮助,更快地浏览页面(在数据库中,这是“差的select性”)。
- 对于一本10页的书来说,做一个索引是没有意义的,因为你最终可能会得到一本10页的书,前面有一个5页的索引,这只是愚蠢的 – 只是扫描10页,并完成它。
- 该索引也需要有用 – 通常没有意义,例如每页的字母“L”的频率。
你必须知道的第一件事是索引是避免扫描整个表来获得你要找的结果的一种方法。
有不同种类的索引,它们在存储层中实现,因此它们之间没有标准,它们也依赖于您正在使用的存储引擎。
InnoDB和B +树索引
对于InnoDB,最常见的索引types是基于B +树的索引,它按sorting顺序存储元素。 另外,你不必访问真正的表来获得索引值,这使得查询返回的方式更快。
关于这个索引types的“问题”是你必须查询最左边的值来使用索引。 所以,如果你的索引有两列,比如last_name和first_name,那么你查询这些字段的顺序就很重要 。
所以,给出下表:
CREATE TABLE person ( last_name VARCHAR(50) NOT NULL, first_name VARCHAR(50) NOT NULL, INDEX (last_name, first_name) );
这个查询将利用索引:
SELECT last_name, first_name FROM person WHERE last_name = "John" AND first_name LIKE "J%"
但是下面的一个不会
SELECT last_name, first_name FROM person WHERE first_name = "Constantine"
因为您首先查询first_name
列,而不是索引中最左边的列。
最后一个例子更糟糕:
SELECT last_name, first_name FROM person WHERE first_name LIKE "%Constantine"
因为现在,您正在比较索引中最右边字段的最右边部分。
哈希索引
这是一个不同的索引types,不幸的是,只有内存后端支持。 它闪电般快,但只对完整查找有用,这意味着您不能将其用于>
, <
或LIKE
。
由于它只适用于内存后端,所以你可能不会经常使用它。 我现在可以想到的主要情况是你在内存中创build一个临时表,并使用另一个select的一组结果,并使用散列索引在这个临时表中执行很多其他select。
如果你有一个很大的VARCHAR
字段,你可以在使用B-Tree的时候“模拟”一个哈希索引的使用,方法是创build另一个列并保存一个哈希值。 假设你在一个字段中存储了一个url,这个值非常大。 您也可以创build一个名为url_hash
的整数字段,并使用像CRC32
这样的散列函数或任何其他散列函数在插入时散列URL。 然后,当你需要查询这个值,你可以做这样的事情:
SELECT url FROM url_table WHERE url_hash=CRC32("http://gnu.org");
上面的例子的问题是,由于CRC32
函数产生一个非常小的哈希值,所以在哈希值中会产生大量的冲突。 如果您需要确切的值,可以通过执行以下操作来解决此问题:
SELECT url FROM url_table WHERE url_hash=CRC32("http://gnu.org") AND url="http://gnu.org";
即使碰撞数量很高,仍然值得哈希值,因为只会执行第二次比较(string一)与重复哈希值的比较。
不幸的是,使用这种技术,你仍然需要点击表格来比较url
字段。
包起来
每次你想谈论优化时,你可能会考虑一些事实:
-
整数比较比string比较方式快。 可以用
InnoDB
中的哈希索引模拟来举例说明。 -
也许,在一个过程中增加额外的步骤使得速度更快,而不是更慢。 可以通过以下事实来说明:可以通过将
SELECT
分解为两个步骤来优化SELECT
,使第一个将值存储在新创build的内存表中,然后在第二个表上执行较重的查询。
MySQL也有其他的索引,但是我认为B + Tree是有史以来使用最多的,哈希是一个很好的事情,但是你可以在MySQL文档中find其他的索引。
我强烈build议您阅读“高性能MySQL”一书,上面的答案绝对是基于其关于索引的章节。
基本上索引是按顺序sorting的所有键的映射。 按顺序列表,而不是检查每个键,它可以做这样的事情:
1:转到列表的中间 – 比我要找的更高还是更低?
2:如果较高,则进入中间和底部之间的中间点,如果较低,中间和顶部
3:更高还是更低? 再跳到中间点等等
使用该逻辑,您可以按大约7个步骤在sorting列表中查找元素,而不是检查每个项目。
显然有复杂性,但是这给了你基本的想法。
数据库索引或仅索引有助于加速从表中检索数据。 从表中查询数据时,首先MySQL检查索引是否存在,然后MySQL使用索引来select表的确切物理对应行,而不是扫描整个表。
数据库索引类似于书籍的索引。 如果你想find一个主题,你首先在索引中查找,然后打开包含主题的页面,而不扫描整本书。
强烈build议您应该在您经常查询数据的表的列上创build索引。 请注意,所有主键列都自动在表的主索引中。
如果索引有助于加速查询数据,为什么我们不使用索引来查看所有列? 如果你为每一列创build一个索引,MySQL必须build立和维护索引表。 无论何时对表的logging进行更改,MySQL都必须重build索引,这会花费时间以及降低数据库服务器的性能。 创buildMySQL索引
您创build表格时经常创build索引。 MySQL自动添加任何声明为PRIMARY KEY,KEY,UNIQUE或INDEX的列到索引。 另外,您可以将索引添加到已有数据的表中。
为了创build索引,您可以使用CREATE INDEX语句。 以下说明了CREATE INDEX语句的语法:1 2 3
CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name USING [BTREE | HASH | RTREE] ON table_name (column_name [(length)] [ASC | DESC],...)
首先,根据表types或存储引擎指定索引:
UNIQUE意味着MySQL将创build一个约束,索引中的所有值必须是唯一的。 除BDB以外,所有存储引擎都允许重复的NULL值。 FULLTEXT索引仅由MyISAM存储引擎支持,并且只在数据types为CHAR,VARCHAR或TEXT的列上接受。 SPATIAL索引支持空间列,可在MyISAM存储引擎上使用。 另外,列值不能为NULL。
然后,在USING关键字(如BTREE,HASH或RTREE)之后,也可以根据表的存储引擎命名索引及其types。
下面是表格中的存储引擎和相应的允许索引types:存储引擎允许索引typesMyISAM BTREE,RTREE InnoDB BTREE存储器/堆栈HASH,BTREE NDB哈希
第三,你声明你想添加到索引的表名和列表。 在MySQL中创build索引的示例
在示例数据库中,可以使用CREATE INDEX语句将employees表的officeCode列添加到索引,如下所示:1
CREATE INDEX officeCode ON employees(officeCode)
删除索引
除了创build索引外,还可以使用DROP INDEX语句删除索引。 有趣的是,DROP INDEX语句也映射到ALTER TABLE语句。 以下是删除索引的语法:1
DROP INDEX index_name ON table_name
例如,如果要删除上面创build的employees表的索引officeCode,则可以执行以下查询:1
DROP INDEX officeCode ON employees
看看这个链接: http : //dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
他们是如何工作的,在一个SO职位上涵盖的范围太广。
这是我见过的最好的索引之一。 不幸的是它是用于SQL Server而不是MySQL。 我不确定这两个人有多相似
请参阅此video以获取有关索引的更多详细信息
简单索引您可以在表上创build唯一索引。 唯一索引意味着两行不能有相同的索引值。 这是在表上创build索引的语法
CREATE UNIQUE INDEX index_name ON table_name ( column1, column2,...);
您可以使用一个或多个列来创build索引。 例如,我们可以使用tutorial_author在tutorials_tbl
上创build一个索引。
CREATE UNIQUE INDEX AUTHOR_INDEX ON tutorials_tbl (tutorial_author)
您可以在表格上创build一个简单的索引。 只要从查询中省略UNIQUE关键字来创build简单的索引。 简单的索引允许表中的重复值。
如果要按降序对列中的值进行索引,则可以在列名后添加保留字DESC。
mysql> CREATE UNIQUE INDEX AUTHOR_INDEX ON tutorials_tbl (tutorial_author DESC)