7.1 指数出现的原因

没有它就没有数据库的另一个重要的事情是索引。

想象这样一种情况, user表中有 1000 万用户,你想显示所有级别在 90 以上的用户。这个查询写起来很简单:

SELECT * FROM user WHERE level > 90

太好了,我们在不到一分钟的时间内就写好了请求。从 SQL 服务器执行此查询需要多长时间?要执行这样的查询,他要翻一千万条记录,就算只有一条记录,也需要很多时间。

我们如何在 Java 中完成类似的任务?我们首先将用户集合按级别排序,然后我们可以使用二分查找非常快速地找到所需的记录。我希望我不需要解释它是什么?

很好,但是如果我们现在需要选择注册日期在 2020 年之前的用户怎么办?按注册日期再次排序并使用二进制搜索。

是的,如果我们对某个字段执行过滤,而且不是一次,而是经常,那么存储按该字段排序的数据将非常有用。

以及如何存储按不同字段同时排序的数据?

答案很简单——你需要存储的不是数据本身,而是它们在某个全局表中的索引。

假设有 10 个用户的 id:{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

然后你决定按级别对它们进行排序,那么它们的 id 数组将是,例如,像这样:{9, 2, 3, 1, 5, 4, 8, 6, 7, 10}

如果我们按日期对它们进行排序,那么我们会得到,例如:{10, 1, 8, 7, 2, 3, 5, 9, 6}

这些 id 的数组称为 indexes。元素本身很大,我们不去碰它们。在 Java 中,我们不接触对象,而是存储它们的引用;在 SQL 中,我们不接触真正的字符串,而是存储它们的数字。

让我用 Java 代码重写它:

List<String> list = List.of("A", "C", "B", "Z", "Cc", "Bb", "Zz", "Y");  //this is a list of objects
List<String> alphabeticsList = new ArrayList(list);
Collections.sort(alphabeticsList); //collection sorted alphabetically

List<String> lengthList = new ArrayList(list);
Collections.sort(lengthList, lengthComparator); //collection sorted by string length

排序集合并不意味着移动实际元素。该集合不存储真实的对象,但链接到它们。SQL 表也是如此。实线自欺欺人。

而当我们需要频繁地对某个字段进行选择时,我们会在表中添加另一个索引(类似于 Java 中的新集合)并对表中的行进行排序,并将它们的排序顺序存储在一个特殊的索引文件中。

我希望 Java 比较有所帮助。一点实践——对你来说,索引的使用也将成为最明显的解决方案。

7.2 为表添加索引

索引可以在创建表时立即指定,也可以在创建之后添加。最常见的是第二种情况——随着表大小的增长和数据采样速度的减慢,索引被添加。

为表添加索引非常简单:

ALTER TABLE table
    ADD INDEX index_name (column);

如果经常同时查找多列记录,可以指定复合索引:SQL使用多列组合而成。

给表添加复合索引也很简单:

ALTER TABLE table
    ADD INDEX index_name (column 1, column 2, column 3, ...);

索引占用大量磁盘空间,因此如果您不再需要某个索引,可以随时将其删除:

ALTER TABLE table
    DROP INDEX index_name;

索引本身是数据库的一个相当隐藏的部分。它们不会以任何方式影响编写查询的格式。只是它们的存在加快了数据采样的速度,减慢了它们的添加和备份速度。

但考虑到当今世界速度的重要性以及磁盘空间的廉价程度,请随意为所有场合添加索引。管理员见谅...