MySQL Index--InnoDB引擎的主键索引

无主键表

在Innodb存储引擎中,每张表都会有主键,数据按照主键顺序组织存放,该类表成为索引组织表 Index Ogranized Table

如果表定义时没有显示定义主键,则会按照以下方式选择或创建主键:

a) 先判断表中是否有"非空的唯一索引",如果有
    1) 如果仅有一条"非空唯一索引",则该索引为主键
    2) 如果有多条"非空唯一索引",根据索引索引的先后顺序,选择第一个定义的非空唯一索引为主键。
b) 如果表中无"非空唯一索引",则自动创建一个6字节大小的指针作为主键。

如果主键索引只有一个索引键,那么可以使用_rowid来显示主键,如:

## 删除测试表
DROP TABLE IF EXISTS tb2001;

## 创建测试表
CREATE TABLE `tb2001` (
    `id` int(11) NOT NULL,
    `c1` int(11) DEFAULT NULL,
    UNIQUE uni_id (id),
    INDEX idx_c1(c1)
) ENGINE = InnoDB CHARSET = utf8;

## 插入测试数据
INSERT INTO tb2001 (id, c1)
SELECT 1, 1;

INSERT INTO tb2001 (id, c1)
SELECT 2, 2;

INSERT INTO tb2001 (id, c1)
SELECT 4, 4;

## 查看数据和_rowid
SELECT *, _rowid
FROM tb2001;
+----+------+--------+
| id | c1   | _rowid |
+----+------+--------+
|  1 |    1 |      1 |
|  2 |    2 |      2 |
|  4 |    4 |      4 |
+----+------+--------+

可以发现,上面的_rowid与id的值相同,因为id列是表中第一个唯一且NOT NULL的索引。

强制主键索引

由于主键索引只能为PRIMARY:

SHOW INDEXES IN tb2001 \G
*************************** 1. row ***************************
        Table: tb2001
   Non_unique: 0
     Key_name: PRIMARY
 Seq_in_index: 1
  Column_name: id
    Collation: A
  Cardinality: 2
     Sub_part: NULL
       Packed: NULL
         Null:
   Index_type: BTREE
      Comment:
Index_comment: 

因此在强制走主键索引FORCE INDEX(PRIMARY)时,使用:

SELECT *
FROM tb2001 FORCE INDEX(PRIMARY)
WHERE C1=2;

非聚集索引中的聚集索引键

在MySQL 5.6.9版本前,Innodb的非聚集索引中包含聚集索引的索引键,但只起到通过非聚集索引定位记录的作用,但在MySQL 5.6.9之后版本中,优化器会考虑非聚集索引中包含的聚集索引键来提升查询性能,并提供优化器选项use_index_extensions来开启或关闭该特性。

假设有表TB1(ID,C1,C2), ID为主键聚集索引,然后在列C1建立索引IDX_C1(C1):

在MySQL 5.6版本前,索引类似于IDX_C1(C1) INCLUDE(ID);

在MySQL 5.6版本中,索引类似于IDX_C1(C1,ID);

无论是MySQL 5.5还是MySQL 5.6版本中,非聚集索引上的数据都是先按照非聚集索引键在按照聚集索引键进行排序,即在非聚集索引键上值相同的记录会按照聚集索引进行排序。

对于查询:

SELECT *
FROM TB1
WHERE C1=‘ABC‘
AND ID>10
AND ID<1000

在MySQL 5.5版本中,需要按照索引IDX_C1扫描所有C1=‘ABC‘的记录,再根据ID进行过滤。

在MySQL 5.6版本中,进行按照索引IDX_C1就可以先定位C1=‘ABC‘ AND ID>10的第一条记录,再顺序扫描至C1=‘ABC‘ AND ID<1000的记录,有效减少扫描的数据量。

对于查询:

SELECT *
FROM TB1
WHERE C1=‘ABC‘
ORDER BY ID
LIMIT 1

如果满足C1=‘ABC‘的记录数较多,那么查询在MySQL 5.5版本就会性能极差,而在MySQL 5.6版本中变得性能极好,MySQL 5.5版本可以将IDX_C1(C1)优化为 IDX(C1,ID)。

在MySQL 5.5.14版本进行测试,准备测试数据:

## 删除测试表
DROP TABLE IF EXISTS tb2001;

## 创建测试表
CREATE TABLE `tb2001` (
    `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    `c1` int(11) DEFAULT NULL,
    `c2` int(11) DEFAULT NULL,
    INDEX idx_c1(c1),
    INDEX idx_c2(c2,id)
) ENGINE = InnoDB CHARSET = utf8;

## 插入测试数据(10万左右)
## 如果information_schema.columns数据较少,可以重复多次
INSERT INTO tb2001 (c1,c2)
SELECT 1,1 from information_schema.columns;

测试1:

## 测试SQL 1
SELECT c1,id
FROM tb2001 FORCE INDEX(idx_c1)
WHERE C1=1 and id<2;

## 执行时间超过20MS

## 对应执行计划为:
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tb2001
         type: ref
possible_keys: idx_c1
          key: idx_c1
      key_len: 5
          ref: const
         rows: 44196
        Extra: Using where; Using index

## 对应PROFILING数据为:
+----------------------+----------+----------+------------+--------------+---------------+-------+
| Status               | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out | Swaps |
+----------------------+----------+----------+------------+--------------+---------------+-------+
| starting             | 0.000039 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| checking permissions | 0.000007 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| Opening tables       | 0.000011 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| System lock          | 0.000008 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| init                 | 0.000012 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| optimizing           | 0.000009 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| statistics           | 0.000041 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| preparing            | 0.000012 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| executing            | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| Sending data         | 0.020529 | 0.019997 |   0.000000 |            0 |             0 |     0 |
| end                  | 0.000006 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| query end            | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| closing tables       | 0.000006 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| freeing items        | 0.000020 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| logging slow query   | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| cleaning up          | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |     0 |
+----------------------+----------+----------+------------+--------------+---------------+-------+

测试2:

## 测试SQL:
SELECT c2,id
FROM tb2001 FORCE INDEX(idx_c2)
WHERE C2=1 and id<2;

##执行时间2ms

## 对应执行计划为:
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tb2001
         type: range
possible_keys: idx_c2
          key: idx_c2
      key_len: 9
          ref: NULL
         rows: 1
        Extra: Using where; Using index

## 对应PROFILING数据为:
+----------------------+----------+----------+------------+--------------+---------------+-------+
| Status               | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out | Swaps |
+----------------------+----------+----------+------------+--------------+---------------+-------+
| starting             | 0.000042 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| checking permissions | 0.000007 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| Opening tables       | 0.000012 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| System lock          | 0.000007 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| init                 | 0.000012 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| optimizing           | 0.000008 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| statistics           | 0.000033 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| preparing            | 0.000011 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| executing            | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| Sending data         | 0.000031 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| end                  | 0.000005 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| query end            | 0.000005 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| closing tables       | 0.000006 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| freeing items        | 0.000022 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| logging slow query   | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |     0 |
| cleaning up          | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |     0 |
+----------------------+----------+----------+------------+--------------+---------------+-------+

参考链接:https://dev.mysql.com/doc/refman/5.6/en/index-extensions.html

原文地址:https://www.cnblogs.com/gaogao67/p/11037462.html

时间: 2024-11-10 08:06:07

MySQL Index--InnoDB引擎的主键索引的相关文章

[MySQL] innoDB引擎的主键与聚簇索引

mysql的innodb引擎本身存储的形式就必须是聚簇索引的形式 , 在磁盘上树状存储的 , 但是不一定是根据主键聚簇的 , 有三种情形: 1. 有主键的情况下 , 主键就是聚簇索引 2. 没有主键的情况下 , 第一个非空null的唯一索引就是聚簇索引 3. 如果上面都没有 , 那么就是有一个隐藏的row-id作为聚簇索引 大部分情况下 , 我们建表的时候都会创建主键 , 因此大部分都是根据主键聚簇的 当我们根据主键字段来进行查询时 , 效率是最高的 , 不需要二次查找 , 直接主键字段查询索引

Mysql主键索引、唯一索引、普通索引、全文索引、组合索引的区别

原文:Mysql主键索引.唯一索引.普通索引.全文索引.组合索引的区别 Mysql索引概念: 说说Mysql索引,看到一个很少比如:索引就好比一本书的目录,它会让你更快的找到内容,显然目录(索引)并不是越多越好,假如这本书1000页,有500也是目录,它当然效率低,目录是要占纸张的,而索引是要占磁盘空间的. Mysql索引主要有两种结构:B+树和hash. hash:hsah索引在mysql比较少用,他以把数据的索引以hash形式组织起来,因此当查找某一条记录的时候,速度非常快.当时因为是has

Mysql索引介绍及常见索引(主键索引、唯一索引、普通索引、全文索引、组合索引)的区别

Mysql各种索引区别:普通索引:最基本的索引,没有任何限制唯一索引:与"普通索引"类似,不同的就是:索引列的值必须唯一,但允许有空值.主键索引:它 是一种特殊的唯一索引,不允许有空值. 全文索引:仅可用于 MyISAM 表,针对较大的数据,生成全文索引很耗时好空间.组合索引:为了更多的提高mysql效率可建立组合索引,遵循”最左前缀“原则. Mysql索引概念:说说Mysql索引,看到一个很少比如:索引就好比一本书的目录,它会让你更快的找到内容,显然目录(索引)并不是越多越好,假如这

mysql的INNODB引擎锁的原理试验

mysql的INNODB引擎锁的原理是怎样的,来做个试验. mysql> SELECT VERSION(); +-----------+ | VERSION() | +-----------+ | 5.5.20    | +-----------+ 1 row in set (0.00 sec) CREATE TABLE test ( a INT(5), b VARCHAR(10), c VARCHAR(10) ); INSERT INTO test VALUES(1,'111','111');

MySQL 使用自增ID主键和UUID 作为主键的优劣比较详细过程(从百万到千万表记录测试)

测试缘由 一个开发同事做了一个框架,里面主键是uuid,我跟他建议说mysql不要用uuid用自增主键,自增主键效率高,他说不一定高,我说innodb的索引特性导致了自增id做主键是效率最好的,为了拿实际的案例来说服他,所以准备做一个详细的测试.   作为互联网公司,一定有用户表,而且用户表UC_USER基本会有百万记录,所以在这个表基础上准测试数据来进行测试.            测试过程是目前我想到的多方位的常用的几种类型的sql进行测试,当然可能不太完善,欢迎大家留言提出更加完善的测试方

谈谈 InnoDB引擎中的一些索引策略

如果我们在工作能够更好的利用好索引,那将会极大的提升数据库的性能. 覆盖索引 覆盖索引是指在普通索引树中可以得到查询的结果,不需要在回到主键索引树中再次搜索 建立如下这张表来演示覆盖索引: create table T ( id int primary key, age int NOT NULL DEFAULT 0, name varchar(16) NOT NULL DEFAULT '', index age(age)) engine=InnoDB; 我们执行select * from T w

1226关于count(*)不走主键索引反而走二级索引

转自 http://www.2cto.com/database/201508/433975.html mysqlcount(*)会选哪个索引? 2015-08-19      0个评论    来源:Database.Code   收藏    我要投稿 今天在查询一个表行数的时候,发现count(1)和count(*)执行效率居然是一样的.这跟Oracle还是有区别的.遂查看两种方式的执行计划: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 mysq

唯一索引与主键索引的比较

唯一索引与主键索引的比较 唯一索引唯一索引不允许两行具有相同的索引值.如果现有数据中存在重复的键值,则大多数数据库都不允许将新创建的唯一索引与表一起保存.当新数据将使表中的键值重复时,数据库也拒绝接受此数据.例如,用户表中的身份证(idcard) 列上创建了唯一索引,则所有身份证不能重复 主键索引主键索引是唯一索引的特殊类型.数据库表通常有一列或列组合,其值用来唯一标识表中的每一行.该列称为表的主键.在数据库关系图中为表定义一个主键将自动创建主键索引,主键索引是唯一索引的特殊类型.主键索引要求主

删除指定表的所有索引,包括主键索引,唯一索引和普通索引 ,适用于sql server 2005,

原文:删除指定表的所有索引,包括主键索引,唯一索引和普通索引 ,适用于sql server 2005, --删除指定表中所有索引 --用法:declare @tableName varchar(100) --set @tableName='表名' --表名 ,根据实际情况替换 --exec sp_dropindex @tableName if exists(select 1 from sysobjects where id = object_id('dropindex') and xtype =