您必须知道的第一件事是索引是一种避免扫描整个表以获得您正在寻找的结果的方法。
索引有很多种,它们是在存储层实现的,因此它们之间没有标准,它们也取决于您使用的存储引擎。
InnoDB 和 B+Tree 索引
对于 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)
);
此查询将利用索引:
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"
因为现在,您正在比较索引中最右侧字段的最右侧部分。
哈希索引
不幸的是,这是一种不同的索引类型,只有内存后端支持。它快如闪电,但仅对完整查找有用,这意味着您不能将其用于>、< 或LIKE 等操作。
由于它仅适用于内存后端,您可能不会经常使用它。我现在能想到的主要情况是,您在内存中创建一个临时表,其中包含来自另一个选择的一组结果,并使用哈希索引在这个临时表中执行许多其他选择。
如果您有一个大的VARCHAR 字段,您可以在使用 B-Tree 时“模拟”哈希索引的使用,方法是创建另一列并在其上保存大值的哈希。假设您将 url 存储在一个字段中,并且值非常大。您还可以创建一个名为 url_hash 的整数字段,并在插入 URL 时使用 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";
即使冲突数很高,仍然值得对事物进行哈希处理,因为您只会针对重复的哈希执行第二次比较(字符串一)。
不幸的是,使用这种技术,你仍然需要打表来比较url字段。
总结
您每次谈论优化时可能会考虑的一些事实:
整数比较比字符串比较快。可以用InnoDB中的hash索引模拟的例子来说明。
也许,在流程中添加额外的步骤会使其更快,而不是更慢。这可以通过以下事实来说明:您可以通过将SELECT 拆分为两个步骤来优化它,使第一个将值存储在新创建的内存表中,然后在第二个表上执行更重的查询。
MySQL 也有其他索引,但我认为 B+Tree 索引是最常用的,而哈希索引是一件好事,但您可以在 MySQL documentation 中找到其他索引。
我强烈推荐你阅读“高性能 MySQL”这本书,上面的答案肯定是基于它关于索引的章节。