MySQL是为主键创建额外的索引还是将数据本身用作“索引”

时间:2019-07-21 15:07:54

标签: mysql primary-key

不能找到一个明确的答案。 我知道,当您创建主键时,MySQL根据该主键对数据进行排序,问题是,它实际上是创建另一个索引还是使用实际数据作为索引,因为它应该由主键进行排序?

编辑:

如果我有一个具有索引A和索引B且没有主键的表,则我具有数据+索引A +索引B。如果我更改该表以将索引A的列作为主键,则仅有数据(也用作索引)+索引B对吗?以上是根据内存使用情况

3 个答案:

答案 0 :(得分:3)

Clustered and Secondary Indexes

  

每个InnoDB表都有一个特殊的索引,称为聚簇索引,用于存储行数据。通常,聚簇索引与主键同义。为了从查询,插入和其他数据库操作中获得最佳性能,您必须了解InnoDB如何使用聚簇索引来优化最常见的查询和DML操作每个表。

     
      
  • 在表上定义主键时,InnoDB会将其用作聚簇索引
  •   
  • 如果您没有为表定义PRIMARY KEY,则MySQL会在所有键列都不为NULL的情况下找到第一个UNIQUE索引,InnoDB会将其用作聚集索引。

  •   
  • 如果表没有PRIMARY KEY或合适的UNIQUE索引,InnoDB会在包含行ID值的综合列上内部生成一个隐藏的聚集索引GEN_CLUST_INDEX。是InnoDB分配给这样一个表中的行的。行ID是一个6字节的字段,随着插入新行而单调增加。因此,按行ID排序的行实际上在插入顺序上。

  •   
     

聚集索引如何加快查询速度

     

通过聚集索引访问行是快速的,因为索引搜索直接导致包含所有行数据的页面。如果表很大,则聚集索引体系结构通常会节省磁盘I /与使用不同于索引记录的页面存储行数据的存储组织进行比较时的操作。

答案 1 :(得分:1)

  

如果我有一个具有索引A和索引B且没有主键的表,则我具有数据+索引A +索引B。如果我更改该表以将索引A的列作为主键,则仅有数据(也用作索引)+索引B对吗?以上是根据内存使用情况

是的,聚集索引的索引是表本身。那是其他未索引列存储的唯一位置。当您显示表状态时,您会看到此报告为df。二级索引报告为Data_length

Index_length

InnoDB始终存储聚集索引。如果您在表的任何列上均未定义PRIMARY KEY,则InnoDB会创建一个人工列作为聚簇索引的键,并且无法查询此列。

答案 2 :(得分:1)

  

如果我有一个具有索引A和索引B并且没有主键的表,我   有数据+索引A +索引B。如果我将表更改为   索引A的列作为主键,我将只有数据(即   也用作索引)+索引B对吗?以上是关于   内存使用量

这是事实-在存储大小方面还有更多需要考虑的地方。

假设,您尝试执行的操作在逻辑上没问题,并且您想要提升为主键的索引实际上是candidate key。是否可以节省存储空间,取决于索引数和主键列的大小。原因是 InnoDB 将主键列附加到每个辅助索引(如果它们尚未明确地包含在其中)。如果其他表(大表)需要将其作为外键引用,它也会影响其他表。

这里有一些简单的测试,可以显示差异。我正在使用MariaDB,因为它是 sequence插件,可轻松创建虚拟数据。但是您应该在MySQL服务器上看到相同的效果。

因此,首先,我将创建一个具有两个INT列的简单表,并在每个表上填充100K行。

drop table if exists test;
create table test(
    a int,
    b int,
    index(a),
    index(b)
);

insert into test(a, b)
    select seq as a, seq as b
    from seq_1_to_100000
;

为简单起见,我只看表的文件大小(我正在使用innodb_file_per_table=1)。

16777216 test.ibd

现在让我们做您想做的,并使列a为主键,更改CREATE语句:

create table test(
    a int,
    b int,
    primary key(a),
    index(b)
);

文件大小现在为:

13631488 test.ibd

是的,您可以-通过提升主键索引来节省存储空间。在这种情况下,将近20%。

但是,如果我将列类型从INT(4字节)更改为BINARY(32)(32字节),会发生什么?

create table test(
    a binary(32),
    b binary(32),
    index(a),
    index(b)
);

文件大小:

37748736 test.ibd

现在使列a为主键

create table test(
    a binary(32),
    b binary(32),
    primary key(a),
    index(b)
);

文件大小:

41943040 test.ibd

如您所见,您也可以增加大小。在这种情况下,就是11%。

尽管建议始终定义一个主键。如有疑问,只需创建一个AUTO_INCREMENT PRIMARY KEY。在我的示例中,可能是:

create table test(
    id mediumint auto_increment primary key,
    a binary(32),
    b binary(32),
    index(a),
    index(b)
);

文件大小:

37748736 test.ibd

大小与没有显式主键时的大小相同。 (尽管我希望节省一些空间,因为我使用3字节PK而不是隐藏的6字节PK。)但是现在您可以在查询中将其用于外键和联接。