作为一名数据科学家,您经常需要处理海量数据。处理如此庞大的数据绝非易事。为了尽可能高效地处理它,您需要清楚了解数据在物理层面的组织方式,这样才能运用顺手的技术来处理。
SQL 是现代软件工程师必备的技能,因为大多数软件都依赖某种数据,并且能与 RDBMS(关系型数据库管理系统)很好地集成。无论是 Web 应用、API,还是内部应用,RDBMS 始终存在。而 SQL 则是查询 RDBMS 的语言。
对数据科学家来说,掌握 SQL 及其相关技术至关重要。为了能查询 RDBMS 并获取您对所处理数据的特定问题的答案,SQL 是最低限度的需求。
在他与 DataCamp 最新的视频中,David Robinson(DataCamp 首席数据科学家)向我们展示了他如何在一个数据科学问题中使用 SQL。请务必看看。他的工作流程非常有趣。
今天,您将学习一种名为索引的技术,它主要涉及数据库内部的数据组织方式,同时您还将使用 SQL 实现其中的一些方法。这将帮助您了解如何利用索引在数据库中存储信息,以及它如何带来更快的执行时间。
注意:在开始阅读本教程之前,强烈建议您先了解 SQL 基础知识(如果您还不熟悉)。DataCamp 的 数据科学 SQL 入门课程是复习 SQL 基础的优秀资源。
关于文件中记录组织的一点说明
在开始学习索引之前,了解数据在文件内部的物理组织方式至关重要。显然,您不会深入到所有细节,但对组织方式有一个良好的概览将有助于您清晰地理解索引。让我们开始吧。
记录/数据的一般组织方式涉及记录如何存储,大体可分为两类:
即便文件是有序组织的,如果文件的块大小以及每条记录的大小都非常大,会怎样?我们在下一节来探讨。
索引的必要性
本节将从使用索引以高效存储文件/信息的动机讲起,并说明它如何提升与这些文件/信息相关的其他操作。
设想在数据库中有一张包含多条记录的表(关系)。这些记录又被划分为 1000 个块。图示组织如下:

从上面的组织可以看出:
- 排序应用于记录的第一列(假设这是一个以表格形式组织数据的关系型数据库系统)
- 总数据被划分的块数为:1000 个块。
请记住,每条记录还包含其他列,但在该组织中,排序应用于第一列,块据此划分。现在,如果您使用二分查找在这种记录组织中搜索内容,总耗时为 $\log_{2}1000$,也就是 10 个时间单位。这个搜索时间还能改进吗?
当然可以。
不妨把它类比为读书却没有索引页。您随机翻到一页(或者在二分查找中翻到书的中间),再根据需要向左或向右翻,直至找到目标页。这显然要花时间,对吧?
但如果书中有索引页,搜索会更高效。您可以通过查找索引直接翻到目标页。上述情境中同样可以应用索引思想。
以下是您在此处应用索引的概要:
这将使用于存储数据文件的块数量减少。现在,为了搜索某条特定记录,您只需在由较少块组成的新组织中搜索,最终就能以更少的时间找到目标记录(如果存在)。我们来把它可视化。假设新建的索引记录最终为 8 个块,组织将如下所示:

块数更少意味着搜索时间将大幅降低。假设您要搜索记录 90。在这个新的索引方案中,您首先定位其对应的块指针(此例为 3),然后利用该信息一次就能找到原始数据记录。
因此,本例中的搜索时间为 $\log_{2}8 + 1$ = 4 个时间单位,与之前相比显著减少。
上述例子说明了进行索引的必要性。以下是一些值得注意的要点:
- 对原始数据记录的排序只能基于一个字段。随后可以按该字段建立索引。只有当您使用该字段进行搜索时,搜索时间才会得到改进。(极其重要)
- 索引本身也是有序的。
- 索引记录包含两个字段(索引文件的结构):
- 通过索引使用二分查找进行搜索。
- 使用索引项访问一条记录,平均所需的块访问次数为:$\log_{2}B_i + 1$,其中 $B_i$ 为索引记录中的块数
- 可以在关系的任意字段(主键、候选键、非键)上创建索引。
现在,根据原始数据记录的排序方式以及您在索引文件中维护多少记录,可以设计多种索引方案。下一节将介绍最常见的几种。
不同的索引策略:
- 稠密索引(Dense Indexing):如果为每个搜索键值都创建索引项,则为稠密索引。请参考下图以获得直观理解。

- 稀疏索引(Sparse Indexing):如果只为部分记录创建索引项,则为稀疏索引。下图给出了示意。

上述图示使两种索引方案都易于理解。这里需要强调一点:上述稀疏索引示例其实是稠密与稀疏的组合。这是因为对于每个唯一的搜索键值(1、2 和 3)都有索引,但并非每条数据记录都有索引。
接下来,您将按记录层级来学习其他类型的索引方案。在单级索引中,索引文件只有一个。但有时索引文件会变得非常大,以至于索引文件本身也需要被索引。在这种情况下称为多级索引。让我们进一步探究。
以下是基于层级划分的索引策略概览。
单级索引:
- 主索引(Primary indexing)
- 聚簇索引(Clustered indexing)
- 辅助索引(Secondary indexing)
多级索引:
您将学习属于单级索引的所有策略。教程末尾会提供链接,供您在有兴趣时探索多级索引方案。现在先来看主索引。
主索引:
主索引是一个有序文件,其记录为固定长度,包含两个字段:
- 第一个字段与数据文件的主键相同。
- 第二个字段是指向主键所在数据块的指针。- 来源
为每个块的第一条记录创建的索引称为块锚(block anchors)。在主索引中,索引项数量 = 原始数据块的数量。使用主索引进行访问的平均块访问次数为:
$\log_{2}B_i + 1$,其中 $B_i$ 为索引记录中的块数。
请参考下图以更清晰地理解:
最右侧的图示为被划分为多个块的原始数据记录。注意包含数字 1、2、3、…、9 的列为主键。最左侧的图示为索引项,每个索引项包含:
- 每个数据块的第一条记录(块锚)
- 第二个条目表示块指针。
请花点时间思考这属于哪种索引(稀疏还是稠密)。欢迎在评论区留言。
现在来学习聚簇索引。
聚簇索引:
聚簇索引建立在这样的数据文件之上:其文件记录在物理上按照某个非键字段排序,而该字段对每条记录并不具有唯一值。基于该字段进行索引,该字段称为聚簇字段,因此得名聚簇索引。

图示总能让理解更容易。正如您所见,原始数据记录按某个非键属性排序,并且对该非键属性的每个不同取值都创建一个索引项。使用该方案定位特定记录所需的平均块访问次数为 $\geq$ $\log_{2}B_i + 1$,其中 $B_i$ 为索引记录中的块数。请注意这里的 $\geq$ 符号。
在聚簇索引中,在定位到包含某个键的块之后,您可能还需要遍历其他块(从上图也能明显看出)。
您不妨思考一下这属于哪种索引(稀疏还是稠密)。欢迎在评论区留言。现在来学习辅助索引。
辅助索引:
假设您的数据库中有一张名为 Employee 的表。该表包含以下属性:
- employee_id
- employee_name
- employee_department
- employee_salary
employee_id 是其主键。现在,您已经基于 employee_id 为该表创建了主索引。但在开发应用时,您发现大多数数据库查询都在使用 employee_name 属性。在这种情况下,主索引作用不大,为 employee_name 的所有取值维护单独的索引会是更好的做法。无论如何,员工姓名在数据库中并不会按有序方式存放。因此,对其建立索引无疑会加速涉及员工姓名的查询。
这就是辅助索引的经典示例。我们也来构建一张合适的示意图:

如果您有更好的表示方式,欢迎在评论区分享。
接下来看看如何在 PostgreSQL 中创建索引。如果您想掌握其基础知识,可以学习 DataCamp 的 在 PostgreSQL 中进行表连接课程。
在 PostgreSQL 中创建索引
在 PostgreSQL 数据库中开始创建索引之前,您需要在表中准备一些数据。我们来创建一张名为 Student 的简单表,包含以下记录字段:
- student_id
- student_name
- student_year
您将把 student_id 设为主键,并且不允许学生姓名和入学年为空。
对应的查询如下:
CREATE TABLE STUDENT(
student_id TEXT PRIMARY KEY,
student_name TEXT NOT NULL,
student_year TEXT NOT NULL
);
技术支持
表创建成功后,您需要向表中插入一些合适的数据。为方便起见,您可以使用一个 .csv 文件并将其导入 Student。您可以使用以下查询将兼容的 .csv 文件导入 PostgreSQL 表:
COPY STUDENT FROM '/path/to/csv/Student.csv' WITH (FORMAT csv);
技术支持
上述查询假定用于复制数据的 .csv 文件名为 Student。
现在来看一下数据。运行 select * from STUDENT; 返回如下记录:
select 查询应返回共 86 条记录。现在,您可以开始创建索引了。您可以使用以下语法创建单列索引:
CREATE INDEX index_name
ON table_name (column_name);
技术支持
我们在 student_id 字段上创建索引(主索引)。
CREATE INDEX id_index
ON STUDENT (student_id);
技术支持
也可以创建多列索引:
CREATE INDEX id_index
ON STUDENT (student_id,student_name);
技术支持
您可以使用以下语法删除索引:
DROP INDEX index_name;
技术支持
在像 STUDENT 这样的小表中,很难直观感受到索引的作用。但如果表很大(例如包含一所大型大学类似记录的数据库表),索引无疑会发挥关键作用。
您做到了!
恭喜您读到最后。在本教程中,您学习了索引、索引的必要性以及不同的索引方案。您还看到了如何在 PostgreSQL 中执行简单的索引。
不过,本教程未涉及多级索引。如果您有兴趣探索,以下是一些优秀资源:
但使用索引总是有益的吗?其实在某些情况下,不建议使用索引。

来源
希望本教程能帮助您厘清索引的基础。欢迎在评论区分享您的有趣发现。
查看 DataCamp 的 SQL 学习中心。
作为一名数据科学家,您经常需要处理海量数据。处理如此庞大的数据绝非易事。为了尽可能高效地处理它,您需要清楚了解数据在物理层面的组织方式,这样才能运用顺手的技术来处理。
SQL 是现代软件工程师必备的技能,因为大多数软件都依赖某种数据,并且能与 RDBMS(关系型数据库管理系统)很好地集成。无论是 Web 应用、API,还是内部应用,RDBMS 始终存在。而 SQL 则是查询 RDBMS 的语言。
对数据科学家来说,掌握 SQL 及其相关技术至关重要。为了能查询 RDBMS 并获取您对所处理数据的特定问题的答案,SQL 是最低限度的需求。
在他与 DataCamp 最新的视频中,David Robinson(DataCamp 首席数据科学家)向我们展示了他如何在一个数据科学问题中使用 SQL。请务必看看。他的工作流程非常有趣。
今天,您将学习一种名为索引的技术,它主要涉及数据库内部的数据组织方式,同时您还将使用 SQL 实现其中的一些方法。这将帮助您了解如何利用索引在数据库中存储信息,以及它如何带来更快的执行时间。
注意:在开始阅读本教程之前,强烈建议您先了解 SQL 基础知识(如果您还不熟悉)。DataCamp 的 数据科学 SQL 入门课程是复习 SQL 基础的优秀资源。
关于文件中记录组织的一点说明
在开始学习索引之前,了解数据在文件内部的物理组织方式至关重要。显然,您不会深入到所有细节,但对组织方式有一个良好的概览将有助于您清晰地理解索引。让我们开始吧。
记录/数据的一般组织方式涉及记录如何存储,大体可分为两类:
有序组织:文件中的所有记录按某个搜索键值排序。通常使用二分查找在有序文件中搜索任何条目。这样搜索非常高效,因为时间复杂度保持在对数时间。但向文件中插入新记录会代价高昂,因为您可能需要重新组织整个文件来容纳新条目。
无序组织:在这种类型中,记录会被插入到文件中的任意可用位置,通常是文件末尾。由于此类使用线性查找,搜索效率不如前者,但插入操作并不昂贵。
即便文件是有序组织的,如果文件的块大小以及每条记录的大小都非常大,会怎样?我们在下一节来探讨。
索引的必要性
本节将从使用索引以高效存储文件/信息的动机讲起,并说明它如何提升与这些文件/信息相关的其他操作。
设想在数据库中有一张包含多条记录的表(关系)。这些记录又被划分为 1000 个块。图示组织如下:
从上面的组织可以看出:
请记住,每条记录还包含其他列,但在该组织中,排序应用于第一列,块据此划分。现在,如果您使用二分查找在这种记录组织中搜索内容,总耗时为 $\log_{2}1000$,也就是 10 个时间单位。这个搜索时间还能改进吗?
当然可以。
不妨把它类比为读书却没有索引页。您随机翻到一页(或者在二分查找中翻到书的中间),再根据需要向左或向右翻,直至找到目标页。这显然要花时间,对吧?
但如果书中有索引页,搜索会更高效。您可以通过查找索引直接翻到目标页。上述情境中同样可以应用索引思想。
以下是您在此处应用索引的概要:
这将使用于存储数据文件的块数量减少。现在,为了搜索某条特定记录,您只需在由较少块组成的新组织中搜索,最终就能以更少的时间找到目标记录(如果存在)。我们来把它可视化。假设新建的索引记录最终为 8 个块,组织将如下所示:
块数更少意味着搜索时间将大幅降低。假设您要搜索记录 90。在这个新的索引方案中,您首先定位其对应的块指针(此例为 3),然后利用该信息一次就能找到原始数据记录。
因此,本例中的搜索时间为 $\log_{2}8 + 1$ = 4 个时间单位,与之前相比显著减少。
上述例子说明了进行索引的必要性。以下是一些值得注意的要点:
现在,根据原始数据记录的排序方式以及您在索引文件中维护多少记录,可以设计多种索引方案。下一节将介绍最常见的几种。
不同的索引策略:
上述图示使两种索引方案都易于理解。这里需要强调一点:上述稀疏索引示例其实是稠密与稀疏的组合。这是因为对于每个唯一的搜索键值(1、2 和 3)都有索引,但并非每条数据记录都有索引。
接下来,您将按记录层级来学习其他类型的索引方案。在单级索引中,索引文件只有一个。但有时索引文件会变得非常大,以至于索引文件本身也需要被索引。在这种情况下称为多级索引。让我们进一步探究。
以下是基于层级划分的索引策略概览。
单级索引:
多级索引:
您将学习属于单级索引的所有策略。教程末尾会提供链接,供您在有兴趣时探索多级索引方案。现在先来看主索引。
主索引:
主索引是一个有序文件,其记录为固定长度,包含两个字段:
为每个块的第一条记录创建的索引称为块锚(block anchors)。在主索引中,索引项数量 = 原始数据块的数量。使用主索引进行访问的平均块访问次数为:
请参考下图以更清晰地理解:
最右侧的图示为被划分为多个块的原始数据记录。注意包含数字 1、2、3、…、9 的列为主键。最左侧的图示为索引项,每个索引项包含:
请花点时间思考这属于哪种索引(稀疏还是稠密)。欢迎在
评论区留言。现在来学习聚簇索引。
聚簇索引:
聚簇索引建立在这样的数据文件之上:其文件记录在物理上按照某个非键字段排序,而该字段对每条记录并不具有唯一值。基于该字段进行索引,该字段称为聚簇字段,因此得名聚簇索引。
图示总能让理解更容易。正如您所见,原始数据记录按某个非键属性排序,并且对该非键属性的每个不同取值都创建一个索引项。使用该方案定位特定记录所需的平均块访问次数为 $\geq$ $\log_{2}B_i + 1$,其中 $B_i$ 为索引记录中的块数。请注意这里的 $\geq$ 符号。
在聚簇索引中,在定位到包含某个键的块之后,您可能还需要遍历其他块(从上图也能明显看出)。
您不妨思考一下这属于哪种索引(稀疏还是稠密)。欢迎在评论区留言。现在来学习辅助索引。
辅助索引:
假设您的数据库中有一张名为
Employee的表。该表包含以下属性:employee_id 是其主键。现在,您已经基于 employee_id 为该表创建了主索引。但在开发应用时,您发现大多数数据库查询都在使用 employee_name 属性。在这种情况下,主索引作用不大,为 employee_name 的所有取值维护单独的索引会是更好的做法。无论如何,员工姓名在数据库中并不会按有序方式存放。因此,对其建立索引无疑会加速涉及员工姓名的查询。
这就是辅助索引的经典示例。我们也来构建一张合适的示意图:
如果您有更好的表示方式,欢迎在
评论区分享。接下来看看如何在 PostgreSQL 中创建索引。如果您想掌握其基础知识,可以学习 DataCamp 的 在 PostgreSQL 中进行表连接课程。
在 PostgreSQL 中创建索引
在 PostgreSQL 数据库中开始创建索引之前,您需要在表中准备一些数据。我们来创建一张名为
Student的简单表,包含以下记录字段:您将把
student_id设为主键,并且不允许学生姓名和入学年为空。对应的查询如下:
表创建成功后,您需要向表中插入一些合适的数据。为方便起见,您可以使用一个 .csv 文件并将其导入
Student。您可以使用以下查询将兼容的 .csv 文件导入 PostgreSQL 表:上述查询假定用于复制数据的 .csv 文件名为 Student。
现在来看一下数据。运行
select * from STUDENT;返回如下记录:select查询应返回共 86 条记录。现在,您可以开始创建索引了。您可以使用以下语法创建单列索引:我们在
student_id字段上创建索引(主索引)。也可以创建多列索引:
您可以使用以下语法删除索引:
在像
STUDENT这样的小表中,很难直观感受到索引的作用。但如果表很大(例如包含一所大型大学类似记录的数据库表),索引无疑会发挥关键作用。您做到了!
恭喜您读到最后。在本教程中,您学习了索引、索引的必要性以及不同的索引方案。您还看到了如何在 PostgreSQL 中执行简单的索引。
不过,本教程未涉及多级索引。如果您有兴趣探索,以下是一些优秀资源:
但使用索引总是有益的吗?其实在某些情况下,不建议使用索引。
希望本教程能帮助您厘清索引的基础。欢迎在
评论区分享您的有趣发现。查看 DataCamp 的 SQL 学习中心。