【问题标题】:Clustered Indexing in MySQLMySQL 中的聚集索引
【发布时间】:2019-05-20 08:20:02
【问题描述】:

我正在学习数据库中的索引。 根据 GeeksforGeeks (https://www.geeksforgeeks.org/indexing-in-databases-set-1/) ,为聚集索引创建索引文件。有一张图表显示了第 1-8 学期的索引文件。

但在阅读https://use-the-index-luke.com/blog/2014-01/unreasonable-defaults-primary-key-clustering-key时,提到了

如果一个表有聚集索引,基本上就说明这个索引就是那个表

我想知道在聚集索引和非聚集索引中是否生成索引文件?

另外,我们可以看到表上的索引文件,即它存储的内容吗?

【问题讨论】:

标签: mysql database indexing clustered-index


【解决方案1】:

从 MySQL 用户的角度来看,聚集索引的这项业务是一个实现细节。

表中的信息必须存储在 SSD 或硬盘驱动器等存储设备的某个位置。很大程度上取决于数据库服务器的版本和使用的特定访问方法(InnoDB、MyISAM...)。

有些信息是元数据:表的描述。 MySql 经常将其存储在 table.frm 文件中。行中的信息通常存储在容器文件tablename.ibd 中。这些文件只能由 MySQL 服务器或为此目的构建的其他软件解释;如果 MySQL 服务器处于活动状态,典型的独立程序无法理解它们尤其是。换句话说:如果您编写程序来更改这些文件中的任何一个,您损坏您的数据库并丢失表的内容。

在容器文件中是 MySQL 的访问方法代码访问的一些数据结构。通常,具有主键的表被存储起来,就好像它们是索引一样,每行的所有数据都挂在每个索引条目上。该数据结构是一个聚集索引。

您不一定要查看运行 MySQL 服务器的机器的文件系统并指向包含索引或聚集索引或其他任何内容的特定文件。使用 InnoDB,您可以使用 TABLESPACE commands 指示 MySQL 将数据放入文件系统中的特定文件中。但是从 MySQL 8 开始,没有办法将索引放在自己的表空间中。

(Oracle 和 MS SQL Server 企业版等产品的数据库管理员通过将表空间移动到不同的磁盘驱动器来优化和并行化访问。这在 MySQL 中并不是什么大问题,直到您的表开始占用磁盘驱动器的很大一部分空间。)

【讨论】:

    【解决方案2】:

    我想知道在聚集索引和非聚集索引中是否生成索引文件?

    MySQL 中的 InnoDB 表(默认引擎类型)始终是集群的。这意味着索引存储所有表列;不需要单独的“堆”表。如果您使用旧的 MyIsam 引擎,那么该表将有一个堆,并在其顶部加上任何额外的索引。

    另外,我们可以看到表上的索引文件,即它存储的内容吗?

    “主”索引存储表的所有列:键列和非键列。 “二级”索引可以更有选择性,只存储列的一个子集;但主要的拥有一切。

    【讨论】:

      【解决方案3】:

      MySQL 本质上只有一种索引方法:BTree。 (是的,还有空间和全文,但这是另一个讨论。)

      一旦您了解了 BTree 的工作原理(参见 Wikipedia),我们就可以讨论进入 InnoDB 中叶节点的内容。

      案例 1:“数据”BTree 包含所有列,并根据PRIMARY KEY 排序。在 MySQL 中,PK 是根据定义、“UNIQUE”和“Clustered”。 (其他供应商有其他选择。)

      案例 2:“辅助”INDEX 存储在单独的 BTree 中。叶节点中有 (1) 二级索引中定义的列,以及 PK 列的副本。要使用二级索引完成SELECT,它必须首先使用索引BTree 获取PK,然后通过数据BTree 获取数据。 (如果索引是“覆盖”,则不需要这第二步。)

      MySQL 中没有“Rownum”。

      BTrees 实际上是 B+Trees,从而使范围扫描更有效。

      InnoDB 将给定表的所有 BTree(一个用于数据+PK,一个用于每个二级索引)放入某个表空间。表空间可以是通用的(ibdata1 文件)、特定于表的(文件tablename.ibd)或(在较新版本中)可以包含多个表的“表空间”文件。

      警告:我所描述的适用于 MySQL 的 InnoDB,可能不适用于任何其他引擎。

      我不知道有什么好的工具可以在不深入细节的情况下检查 InnoDB 的 BTree。对于 Percona 版本:

      SELECT  i.INDEX_NAME as Index_Name,
                      IF(ROWS_READ IS NULL, 'Unused',
                          IF(ROWS_READ > 2e9, 'Overflow', ROWS_READ)) as Rows_Read
                  FROM (
                      SELECT DISTINCT TABLE_SCHEMA, TABLE_NAME, INDEX_NAME
                          FROM information_schema.STATISTICS
                       ) i
                  LEFT JOIN information_schema.INDEX_STATISTICS s
                           ON i.TABLE_SCHEMA = s.TABLE_SCHEMA
                          AND i.TABLE_NAME = s.TABLE_NAME
                          AND i.INDEX_NAME = s.INDEX_NAME
                  WHERE i.TABLE_SCHEMA = ?
                    AND i.TABLE_NAME = ?
                  ORDER BY IF(i.INDEX_NAME = 'PRIMARY', 0, 1)
      

      对于 MySQL (Oracle):

      SELECT  last_update,
                      n_rows,
                      'Data & PK' AS 'Type',
                      clustered_index_size * 16384 AS Bytes,
                      ROUND(clustered_index_size * 16384 / n_rows) AS 'Bytes/row',
                      clustered_index_size AS Pages,
                      ROUND(n_rows / clustered_index_size) AS 'Rows/page'
              FROM mysql.innodb_table_stats
              WHERE ( ( database_name = ? AND table_name = ? )
                OR    ( database_name = LOWER(?) AND table_name = LOWER(?) 
          UNION
              SELECT  last_update,
                      n_rows,
                      'Secondary Indexes' AS 'BTrees',
                      sum_of_other_index_sizes * 16384 AS Bytes,
                      ROUND(sum_of_other_index_sizes * 16384 / n_rows) AS 'Bytes/row',
                      sum_of_other_index_sizes AS Pages,
                      ROUND(n_rows / sum_of_other_index_sizes) AS 'Rows/page'
              FROM mysql.innodb_table_stats
              WHERE ( ( database_name = ? AND table_name = ? )
                OR    ( database_name = LOWER(?) AND table_name = LOWER(?) 
                AND sum_of_other_index_sizes > 0
      

      【讨论】:

      • 澄清一下,你是说MySQL自己存储一个聚集索引,我们可以定义非聚集索引吗?此外,在聚集索引的情况下是否生成索引文件(不是强制性的不同文件,而是具有搜索键和指向主表的块指针的表)?我读到它是为非聚集索引生成的,但不确定聚集索引。
      • @kishankeswani - InnoDB 表始终具有聚集索引,并且它与数据(所有列)存储在同一个 BTree 中。一个表可以在不同的 BTree 中具有零个或多个非聚集(“辅助”)索引,但在同一个文件中。
      猜你喜欢
      • 2018-05-22
      • 2017-05-08
      • 1970-01-01
      • 2013-08-07
      • 1970-01-01
      • 2012-11-26
      • 2015-07-31
      • 2018-05-08
      相关资源
      最近更新 更多