`
丁林.tb
  • 浏览: 789198 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

关于InnoDB的索引大小

阅读更多

     这篇文章来自在一个啾啾群纠结的问题。

 

 

背景

         关于InnoDB内的索引大小。对于表

CREATE TABLE `testtb` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a` int(11) DEFAULT NULL,
  `b` int(11) DEFAULT NULL,
  `c` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `i1` (`a`),
  KEY `i2` (`a`,`id`),
  KEY `i3` (`id`,`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

 

 

由于InnoDB在存储索引的时候会自动取出重复的主键,源码分析见这里

先说几个结论

1)       Index i2 由于索引定义中已经包含pk  id,因此不会存两份,实际就是(a, id)

2)       Index i1 本身要包含主键id,因此也是(a, id) i2 相同

3)       同理1,Index i3 里存的也只是(id, a)

 

异常

         按照上面的结论,以下操作能发现“异常”

 

 

 

 

    

CREATE TABLE `t1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a` int(11) DEFAULT NULL,
  `b` int(11) DEFAULT NULL,
  `c` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `i2` (`a`,`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `testtb` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a` int(11) DEFAULT NULL,
  `b` int(11) DEFAULT NULL,
  `c` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `i3` (`id`,`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

  

          接下来往这个两个表中各插入5w行记录,插入语句类似

 

 Foreach I in 1 to 5w
     {
       Set @v = rand() * 100;
       Insert into testtb(a,b,c) values(@v, @v, @v);
     }

 

         插入数据完成后,这个两个表索引大小是否相同?

 

         show table status like ‘%t1%’; show table status like ‘%t2%’;index_length可以看出来,是不同的,t1大一些。

         存储的行数相同,数据也相同,为什么大小不一样?

 

原因说明

         主要在于插入顺序导致的分裂。在上面的例子中,由于a,b,c的值都是随机值,导致索引 (a, id)是随机的。 Id是递增的,所以(id, a)是递增的。

         随机插入索引和顺序递增插入索引之所以有差别,就在于随机插入会导致更多的Btree分裂。

 

这也就是为什么在某些场景下,我们建议在表比较大的应用中,用自增id替代unique key (并非唯一的原因,也不是固定的规范,需要具体分析)

 

验证

有了上面的分析,要验证就比较简单了,把两个表清空(truncate)

插入数据改为如下的语句

 

Foreach I in 1 to 5w
     {
       Set @v = i;
       Insert into testtb(a,b,c) values(@v, @v, @v);
     }

 

 

这样插入的每行都是(n,n,n,n), n15w的递增。这样索引(a, id)也是顺序递增方式,与(id,a)一样紧凑,再看show table status能发现一样了。

 

有个工具

         分两个表验证比较麻烦。这个是之前写过的一个分析文件利用率的工具 ibd_used,可以看一个表上各个索引的大小和索引上page的利用率。

         用法

./ibd_used testtb.ibd 0 N > k

 

说明:第一个参数是要分析的ibd文件

              第二、三个参数是起始、结束page_no  如果你要分析整个文件,N可以输入一个很大的数就行。

               结果中会输出每个page的利用率,因此比较多,记得重定向输出

 

         最后几行是整个索引的统计结果。

 

 

用文章开头的例子和随机值插入的case,得到的表中,执行

 

ibd_used data/test/testtb.ibd 0 99999999 > k
最后几行如下
index_id:1517 rate 1751652/1949696=0.898423
index_id:1518 rate 701314/1212416=0.578443
index_id:1519 rate 701314/1212416=0.578443
index_id:1520 rate 700828/770048=0.910109

 

 

 

 

 按顺序对应索引,可以看出,i1i2的利用率一模一样,但跟i3 比起来就差多了。

 

grep -Po " index_id:\d+" k | sort | uniq -c                                    
    120 index_id:1517
     75 index_id:1518
     75 index_id:1519
     48 index_id:1520

 

 

    这个命令看每个索引占用多少page,与我们的结论一致:i3因为紧凑,所以占用更少的page

5
6
分享到:
评论
8 楼 7先生 2013-04-01  
请问ibd_used这个工具去哪下载?你给的链接好像已经取消分享了。
7 楼 zhoujy 2012-09-21  
丁林.tb 写道
zhoujy 写道
houjy@zhoujy:~$ ll ibd_used
-rwxr-xr-x 1 zhoujy zhoujy 11087 2012-09-20 15:38 ibd_used
zhoujy@zhoujy:~$ md5sum  ibd_used
b90f6a038ea162c102f5abccc332453c  ibd_used

http://pan.baidu.com/share/link?shareid=61749&uk=1191507911 这里下的。

这都对哦。。对了, 你是不是32位系统。。?




是的。原来不适合32位的系统啊,那我还到64位的试试。








6 楼 丁林.tb 2012-09-20  
zhoujy 写道
houjy@zhoujy:~$ ll ibd_used
-rwxr-xr-x 1 zhoujy zhoujy 11087 2012-09-20 15:38 ibd_used
zhoujy@zhoujy:~$ md5sum  ibd_used
b90f6a038ea162c102f5abccc332453c  ibd_used

http://pan.baidu.com/share/link?shareid=61749&uk=1191507911 这里下的。

这都对哦。。对了, 你是不是32位系统。。?
5 楼 zhoujy 2012-09-20  
houjy@zhoujy:~$ ll ibd_used
-rwxr-xr-x 1 zhoujy zhoujy 11087 2012-09-20 15:38 ibd_used
zhoujy@zhoujy:~$ md5sum  ibd_used
b90f6a038ea162c102f5abccc332453c  ibd_used

http://pan.baidu.com/share/link?shareid=61749&uk=1191507911 这里下的。
4 楼 丁林.tb 2012-09-20  
./ibd_used
zhoujy 写道
已经是可执行文件了,但是还是报这个问题。
root@zhoujy:/home/zhoujy# ./ibd_used  /var/lib/mysql/cms/cms_new_block.ibd 0 99999999  > /home/zhoujy/aaa.txt
-bash: ./ibd_used: 无法执行二进制文件

b90f6a038ea162c102f5abccc332453c  ibd_used md5没错吧?

ll ibd_used   输出什么
3 楼 zhoujy 2012-09-20  
已经是可执行文件了,但是还是报这个问题。
root@zhoujy:/home/zhoujy# ./ibd_used  /var/lib/mysql/cms/cms_new_block.ibd 0 99999999  > /home/zhoujy/aaa.txt
-bash: ./ibd_used: 无法执行二进制文件
2 楼 丁林.tb 2012-09-20  
zhoujy 写道
ibd_used 这个工具好像很好用,但是怎么执行报错:
-bash: ./ibd_used: 无法执行二进制文件 

chmod 755 ibd_used
1 楼 zhoujy 2012-09-20  
ibd_used 这个工具好像很好用,但是怎么执行报错:
-bash: ./ibd_used: 无法执行二进制文件 

相关推荐

    浅谈innodb的索引页结构,插入缓冲,自适应哈希索引

    所有的innodb索引都是btree索引,索引记录保存在叶子上,默认的索引页大小是16K。当有新的记录插入时,innodb出于对将来的insert和update操作的考虑,会尝试留下1/16的空闲页大小。 如果索引记录是完全按照索引记录...

    MyISAM InnoDB 区别

    如果是Innodb,恐怕不可能有这么快速度,别和我说让Innodb定期用导出xxx.sql机制备份,因为我平台上最小的一个数据库实例的数据量基本都是几十G大小。  4、从我接触的应用逻辑来说,select count(*) 和order by 是...

    有关MySQL InnoDB在索引中自动添加主键的问题

    (一)原理  只要用户定义的索引字段中包含了主键中的字段,那么这个字段不会再被InnoDB自动加到索引中。但如果用户的索引字段中没有完全...  idx1和idx2两个索引内部大小完全一样,没有区别  例子二: CREA

    InnoDB中文参考手册

    InnoDB 给 MySQL 提供了具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型...InnoDB 表的大小只受限于操作系统的文件大小,一般为 2 GB。

    mysql中关于覆盖索引的知识点总结

    4、覆盖索引对InnoDB尤其有用,因为InnoDB使用聚集索引组织数据,如果二级索引包含查询所需的数据,就不再需要在聚集索引中查找了。 限制: 1、覆盖索引也并不适用于任意的索引类型,索引必须存储列的值。 2、Hash和...

    mysql面试题+BufferPool+InnoDB如何管理Page页+缓冲区+索引页+change buffer更新流程

    其作用是用来缓存表数据与索引数据,减少磁盘IO操作,提升效率。 Buffer Pool由**缓存数据页(Page)** 和 对缓存数据页进行描述的**控制块** 组成, 控制块中存储着对应缓存页的所属的 表空间、数据页的编号、以及...

    MySQL面试题从基础到高阶66问

    InnoDB所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。 2. 事务支持:MyISAM不提供事务支持;InnoDB提供事务支持事务,...

    mysql主从复制

    [root@localhost ~]# vim /etc/my.cnf 1>#skip-networking这个参数作用是是否允许远程访问,如果将#号去掉,将不能访问...7> innodb_buffer_pool_size = 128M共享表空间,表数据,索引存放之地,可以分配内存的50%~80%

    mysql 引擎中的 MyISAM与InnoDB的区别

    InnoDB和MyISAM是许多人在使用MySQL时最常用的两个...InnoDB:所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。 2、 事务支持

    Mysql存储引擎InnoDB和Myisam的六大区别

     基于磁盘的资源是InnoDB表空间数据文件和它的日志文件,InnoDB 表的大小只受限于操作系统文件的大小,一般为 2GB  事务处理上方面:    MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不...

    浅谈MySQL存储引擎选择 InnoDB与MyISAM的优缺点分析

    下面先让我们回答一些问题: ◆你的数据库有外键吗? ◆你需要事务支持吗?... 数据的大小,是一个影响你选择什么样存储引擎的重要因素,大尺寸的数据集趋向于选择InnoDB方式,因为其支持事务处理和故障恢复

    聊聊高并发高可用那些事(Kafka、Redis、MySQL)

    - 为什么表数据删掉一半,表文件大小不变? - 误删表数据除了跑路,还能干啥? - MySQL长连接导致内存溢出? - MySQL自带的数据库 - 代码示例 - MySQL 相关阅读 # Redis篇内容 - 为什么需要缓存 - Redis、Memcached ...

    MySQL学习笔记之为什么表数据删掉一半,表文件大小不变(十三)

    1.参数 innodb_file_per_table ...索引在InnoDB里的数据是用B+树存储的。 当我们删除R4这个记录,InnoDB引擎会把R4,标记为删除,以后再插入一个 ID 在 300-600之间的记录,就会复用这个位置。但是磁盘文件的大小不会

    MySQL经典面试题29道

    因为在InnoDB存储引擎中,主键索引是作为聚簇索引存在的,也就是说,主键索引的B+树叶子节点上存储了主键索引以及全部的数据(按照顺序)。 如果主键索引是自增ID,那么只需要不断向后排列即可。 如果是UUID,由于到来...

    mysql数据库my.cnf配置文件

    #指定用于索引的缓冲区大小,增加它可得到更好处理的索引(对所有读和多重写),到你能负担得起那样多。如果你使它太大, # 系统将开始换页并且真的变慢了。对于内存在4GB左右的服务器该参数可设置为384M或512M。通过...

    2023年最新版-MySQL面试题( 附答案解析)

    InnoDB 底层存储结构为B+树, B树的每个节点对应innodb的一个page, page大小是固定的,一般设 为 16k。其中非叶子节点只有键值,叶子节点包含完成数据 适用场景: 1)经常更新的表,适合处理多重并发的更新请求。 2...

    MySQL高性能优化规范建议

    1. 所有表必须使用 Innodb 存储引擎 2. 数据库和表的字符集统一使用 UTF8 3. 所有表和字段都需要添加注释 4. 尽量控制单表数据量的大小,建议控制在 500 万以内。 5. 谨慎使用 MySQL 分区表 6.尽量做到冷热数据分离,...

    理解MySQL——索引与优化总结

    考虑如下情况,假设数据库中一个表有10^6条记录,DBMS的页面大小为4K,并存储100条记录。如果没有索引,查询将对整个表进行扫描,最坏的情况下,如果所有数据页都不在内存,需要读取10^4个页面,如果这10^4个页面在...

Global site tag (gtag.js) - Google Analytics