SlideShare a Scribd company logo
1 of 39
基于Innodb开发最佳实践

    新媒传信
    吴炳锡
About me
新媒传信(飞信)
 新技术研发部   @吴炳锡   数据库架构师

 职责:
 数据库基础平台研发
 面向公司各部门提供数据库技术支持

 业余:
 北京MySQL活动发起者
大纲
• 案例一:为什么 MySQL这么慢
 – 案例一分析
 – 讨论解决方案
 – 总结经验及运用
• 案例二: 死锁
 – 案例二 分析
 – Innodb锁的类型识别
 – 总结经验及运用
• 总结
案例



案例一:为什么Insert这么慢
案例一:为什么Insert这么慢
• 背景
   向一个表进行insert数据,为啥一秒钟才能写入500条
  (有可能更少)
• 表结构:
  CREATE TABLE `t1_rnd` (
     `id` int(10) unsigned NOT NULL ,
    `c1` varchar(64) NOT NULL,
    `c2` varchar(255) DEFAULT NULL,
      `c3` int(10) unsigned DEFAULT '0',
     PRIMARY KEY (`id`)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
• 写入程序: 备注中
案例一:为什么insert这么慢
$i_end = (int) '999999999‘;
$i_start = 1000000000;
for ($i = $i_start; $i < $i_end; $i++) {
    $x = mt_rand();
 $sql = "INSERT INTO t1_rnd
   VALUES($x, 'name_$x', 'desc_$x', $i)";
 $res = $pdo->exec($sql);
...
}
案例一:为什么insert这么慢
记数从:100000 开始                ok 101282 w, per: 1079 /s
ok 100503 w, per: 12307 /s   ok 101283 w, per: 1093 /s
ok 100504 w, per: 13369 /s   ok 101284 w, per: 836 /s
...                          ok 101285 w, per: 942 /s
ok 100508 w, per: 14082 /s   ok 101286 w, per: 1021 /s
                             ok 101287 w, per: 1033 /s
ok 100509 w, per: 11058 /s
                             ok 101288 w, per: 816 /s
ok 100510 w, per: 12853 /s   ok 101289 w, per: 802 /s
…                            ok 101290 w, per: 1040 /s
ok 101201 w, per: 15592 /s   ok 101291 w, per: 778 /s
ok 101202 w, per: 11037 /s   ok 101292 w, per: 776 /s
ok 101203 w, per: 13454 /s   ...
ok 101204 w, per: 12482 /s   ok 101360 w, per: 618 /s
ok 101205 w, per: 7162 /s    ok 101361 w, per: 611 /s
                             ok 101362 w, per: 580 /s
ok 101206 w, per: 6323 /s
                             ok 101363 w, per: 593 /s
ok 101207 w, per: 4655 /s    ...
ok 101208 w, per: 6212 /s    ok 101372 w, per: 563 /s
ok 101209 w, per: 3960 /s    ok 101373 w, per: 554 /s
ok 101210 w, per: 2559 /s    ok 101374 w, per: 504 /s
ok 101211 w, per: 2170 /s    ok 101375 w, per: 547 /s
...                          ok 101376 w, per: 569 /s
                             ...
案例一分析
• 查看基本情况
 –   mysql> select count(*) from t1_rnd;
 –   +----------+
 –   | count(*) |
 –   +----------+
 –   | 13719413 |
 –   +----------+
 –   1 row in set (12 min 14.59 sec)
• 文件大小:
 – -rw-rw---- 1 mysql3306 mysql 8.5K 08-09 15:01 t1_rnd.frm
 – -rw-rw---- 1 mysql3306 mysql 1.4G 08-09 15:50 t1_rnd.ibd
案例一分析
• 查看基本情况:
 – 通过Percona-Server的慢日值功能可以查看一下count有多少个
   page被读到,读了多少行。
 – mysql>set global log_slow_verbosity=full;
 – mysql>select count(*) from t1_rnd;
 查看慢日值
慢日值内容:
# Thread_id: 36 Schema: wubx Last_errno: 0 Killed: 0
# Query_time: 719.255557 Lock_time: 0.000051 Rows_sent: 1 Rows_examined:
    13719413 Rows_affected: 0 Rows_read: 18446744073693256119
# Bytes_sent: 70 Tmp_tables: 0 Tmp_disk_tables: 0 Tmp_table_sizes: 0
# InnoDB_trx_id: 4A0B331
# QC_Hit: No Full_scan: Yes Full_join: No Tmp_table: No Tmp_table_on_disk: No
# Filesort: No Filesort_on_disk: No Merge_passes: 0
# InnoDB_IO_r_ops: 74732 InnoDB_IO_r_bytes: 1224409088 InnoDB_IO_r_wait:
    713.597767
# InnoDB_rec_lock_wait: 0.000000 InnoDB_queue_wait: 0.000000
# InnoDB_pages_distinct: 65254
SET timestamp=1312882181;
select count(*) from t1_rnd;
• 基本分析:
 mysql> select 65254*16/1024;
 – +---------------+
 – | 65254*16/1024 |
 – +---------------+
 – | 1019.5938 |
 – +---------------+
 计算一下数据大小:
 –   mysql> select (4+30+30+4)*13719413/1024/1024;
 –   +--------------------------------+
 –   | (4+4+30+30)*13719413/1024/1024 |
 –   +--------------------------------+
 –   |               889.70192337 |
 –   +--------------------------------+
案例一分析
• 思考问题:
 – 为什么我们计算需要存储该表的大小和实质物
   理大小相差那么大呢?
   • 是索引增加了文件大小?
 – 为什么count那么慢,Rows_read:
   18446744073693256119 !!!!
案例一分析
• 分析归纳:
 文件大小超过计算:
  • 碎片产生的原因是Innodb表数据本身及索引都属
    于btree结构。
  • Innodb表按主建有序的存放(Cluster Index)
案例一分析
• Count统计太慢:
   • Innodb本身没这方计数器,如果进行无条件
     的count实质上相当于把表的btree page全部
     读取一次。
   • 对于本身碎片很严重的表,这种全表扫描会
     被成一很严重的随机IO操作
   • 那个Read_Rows很大数据,从实质上理解
     是错误的,这就是Bug.
• 从测试数据来看在写入1200万前,性能还能接
  受。
   • 是不是可以考虑对于大表进行拆表处理?
   • 如果该表存在range类的操作,拆表是不是最佳的
     方式呢?
• 对于有碎片明显的表,如何处理能让快点呢?
• 对于无条件count innodb做了什么?
讨论解决方案
看看表碎片比较少的情况的操作:
• 对现存的表碎片整理的操作:
  mysql> alter table theme_irnd engine=Innodb;
  Query OK, 13719413 rows affected (34 min 48.24 sec)
  • 整理后文件大小:
  -rw-rw---- 1 mysql3306 mysql 848M 08-09 18:23 theme.ibd
  mysql> select count(*) from theme;
  +----------+
  | count(*) |
  +----------+
  | 13719413 |
  +----------+
  1 row in set (4.92 sec)

• 如针对range操作,这样是不是已很好了
• 针对range的在加速:
    mysql> create index idx_c3 on t1_rnd(c3);
    Query OK, 0 rows affected (44.37 sec)
    mysql> select count(*) from t1_rnd;
    +----------+
    | count(*) |
    +----------+
    | 13719413 |
    +----------+
    1 row in set (1.84 sec)

• 什么情况,从原来的
   12 min 14.59 sec->4.92 sec->1.84 sec?
讨论解决方案
• 对于无条件count innodb做了什么?
添加完idx_c3索引后:
# Thread_id: 44 Schema: wubx Last_errno: 0 Killed: 0
# Query_time: 1.841461 Lock_time: 0.000051 Rows_sent: 1 Rows_examined:
    13719413 Rows_affected: 0 Rows_read: 13719413
# Bytes_sent: 70 Tmp_tables: 0 Tmp_disk_tables: 0 Tmp_table_sizes: 0
# InnoDB_trx_id: 4A0B89B
# QC_Hit: No Full_scan: Yes Full_join: No Tmp_table: No Tmp_table_on_disk:
    No
# Filesort: No Filesort_on_disk: No Merge_passes: 0
# InnoDB_IO_r_ops: 0 InnoDB_IO_r_bytes: 0 InnoDB_IO_r_wait: 0.000000
# InnoDB_rec_lock_wait: 0.000000 InnoDB_queue_wait: 0.000000
# InnoDB_pages_distinct: 12252
SET timestamp=1312970168;
select count(*) from t1_rnd;
• 为什么用普通索引进行的count比PK快呢?
总结经验及运用
• 总结:
 – 在写入数据时保证主建是有顺的从小到大的方
   式写入
 – 对于Innodb要求快速写入的表添加一列自增的
   自建做为索引
 – 对于Innodb表的使用要保持一个好的习惯,尽
   量基于唯一索引去访问数据(排除range)
 – 如果对于Innodb有大量的update操作,同时又
   有大量的range操作,请考虑定期进行整理碎
   片
总结经验及运用
• 验证:
  同样的表结构,在写入程序做以下调整:
 for ($i = $i_start; $i < $i_end; $i++) {
     $x = $i;
  $sql = "INSERT INTO t1_rnd
    VALUES($x, 'name_$x', 'desc_$x', $i)";
  $res = $pdo->exec($sql);
 ...
 }
总结经验及运用
计数:100000W开始                 ...
ok 100498 w, per: 21769 /s   ok 102991 w, per: 21515 /s
ok 100499 w, per: 21384 /s
ok 100500 w, per: 21770 /s
                             ok 102992 w, per: 21772 /s
ok 100501 w, per: 21376 /s   ok 102993 w, per: 18120 /s
ok 100502 w, per: 21749 /s   ok 102994 w, per: 19615 /s
...                          ok 102995 w, per: 21163 /s
ok 101380 w, per: 21624 /s   ok 102996 w, per: 21782 /s
ok 101381 w, per: 21329 /s   ok 102997 w, per: 21377 /s
ok 101382 w, per: 21632 /s
ok 101383 w, per: 21592 /s
                             ok 102998 w, per: 21705 /s
ok 101384 w, per: 21377 /s   ok 102999 w, per: 13881 /s
ok 101385 w, per: 18434 /s   ok 103000 w, per: 20969 /s
ok 101386 w, per: 19711 /s   ...
...
                             写入到3000W行数据性能也很好
总结经验及运用
• 物理文件大小:
• -rw-rw---- 1 mysql3306 mysql 8.5K 08-09
  15:50 theme.frm
• -rw-rw---- 1 mysql3306 mysql 1.9G 08-09
  16:19 theme.ibd
总结经验及运用
• 运用思考下面类型的表如何设计:
 – 用户表(User)的设计
 – 好友关系表
 – LOG类型的表
总结经验及运用
• 进阶思考:
 – Update会给表带来分页操作吗?
 – Delete会对PAGE有影响吗?


• 如何优化UPDATE&DELETE
案例二:死锁
案例二:死锁
• 背景:
  利用show engine innodb statusG;
  查看LATEST DETECTED DEADLOCK部分经常有死锁现象

  死锁语句:
DELETE FROM GRP_OfflineNotify        WHERE
  UserId = 852577338 AND GroupId = 33990861 AND
  NotifyType = 10
DELETE FROM GRP_OfflineNotify        WHERE
  UserId = 825749088 AND GroupId = 33990861 AND
  NotifyType = 10
案例二 分析
• 了解LATEST DETECTED DEADLOCK :
>show engine innodb statusG;
LATEST DETECTED DEADLOCK
------------------------
这个死锁信息发生的时间
*** (N) TRANSACTION:
   死锁的语句及相关的信息
*** (N) WAITING FOR THIS LOCK TO BE
   GRANTED:
   死锁的原因
案例二 分析
•   死锁原因分析:
mysql> explain select * from GRP_OfflineNotify where UserId=852577338 and
    GroupId=33990861 and NotifyType=10G;
*************************** 1. row ***************************
         id: 1
 select_type: SIMPLE
      table: GRP_OfflineNotify
       type: ref
possible_keys:
    IX_GRP_OfflineNotify_GroupId_NotifyType,IX_GRP_OfflineNotify_UserId
        key: IX_GRP_OfflineNotify_GroupId_NotifyType
    key_len: 5
        ref: const,const
       rows: 1                                          IX_GRP_OfflineNotify_Group
      Extra: Using where                                        Id_NotifyType
1 row in set (0.00 sec)                                      (GroupId, NotifyType)
                                                             普通索引
案例二 分析
• 原因归纳:
     利用
  IX_GRP_OfflineNotify_GroupId_NotifyType索引
  去访问数据,而这个索引并不唯一,所以造成了
  锁的区间较大,造成两个事务相互冲突死锁。

另外:
  也可以参考show engine innodb statusG;中的
 死锁部分中: WAITING FOR THIS LOCK TO BE
 GRANTED
案例二 分析
• 再回到问题上思考:
  这个SQL是做什么的?
  需要锁这么大的区间吗?

• 死锁语句:
DELETE FROM GRP_OfflineNotify
  WHERE         UserId = 852577338 AND
  GroupId = 33990861 AND NotifyType = 10
DELETE FROM GRP_OfflineNotify
  WHERE         UserId = 825749088 AND
  GroupId = 33990861 AND NotifyType = 10
案例二 分析
• 非唯一索引Delete死锁原因:
               root


        brach1
                                    5: col2= 3399086 ,col3=10,…
          Leaf 1
    Sec Ind1          PK     loc   1001:col2= 3399086 ,col3=10,…
                             k
3399086        10     5      X     1006:col2= 3399086 ,col3=10,…
3399086        10     1001   X
3399086        10     1006   X
                                           Table Redords
…
96257735 11           2
6
• 解决办法:
 – 创建新索引:

     create index IX_GRP_OfflineNotify_GroupId
 _UserId_NotifyType on GRP_OfflineNotify(Grou
 pId,UserId,NotifyType);

 – 删除旧索引:

    drop index IX_GRP_OfflineNotify_GroupId_
 NotifyType on GRP_OfflineNotify;
• Innodb支持的锁类型:
 – Record lock
 – Next Key lock
 – Gap lock
 – Table lock

• 高并环境事务隔离级别:
  READ-COMMITTED
Innodb锁的类型识别
• Gap-lock
   – 这个锁影响Insert操作。
   假设一个索引包括5,7利用这个索引访问过的
     取出结果为5,7相关记录,但同时别的
     session需要insert一个索引为6的索引,这个就
     需要等待。
   该锁在:READ-COMMITTED隔离级别下不工作。
• Table-lock
   属于显式声明的,可以忽略。
总结经验及运用
• Innodb索引分情况:
                                                       root
            root

                                                         brach1
       brach1

       Leaf 1                                          Leaf 1
Sec Ind1    PK                        Pk       Table other recoder
1           5                         1        col2=‘wubx’, col3=‘775’,…
5           1                         2        col2=‘liuxin’,col3=‘123’,…
…                                     …
99          2                         5        Col2=‘zbr’,col3=‘1000’…

                   Select * from tb where sec_ind1=1
总结经验及运用
• 变长字段处理:

                    …   Prefix(768B)   …
                                           COMACT

                                                OverFlow
                                                  page
     20 bytes
 …              …
                DYNAMIC

                          OverFlow
                            page
总结经验及运用
• 讨论个问题:
 – 为什么Innodb表设计中有条:没有特殊的理由
   请给该表添加一个自增的例做主建?
 – 那么有特属的理由又是啥呢?
总结经验及运用
• 运用:
 – 养成基于唯一索引访问数据的习惯
 – Update操作不要去update主建
 – 没有特殊的理由请给你的表添加一个无符号自
   增列做为主建
 – 如果大量的查询是基于条件的range操作,请把
   这个索引做为第二索引
基于Innodb开发的最佳实践

More Related Content

What's hot

Mysql introduction-and-performance-optimization
Mysql introduction-and-performance-optimizationMysql introduction-and-performance-optimization
Mysql introduction-and-performance-optimizationisnull
 
Mongo db部署架构之优先方案
Mongo db部署架构之优先方案Mongo db部署架构之优先方案
Mongo db部署架构之优先方案Lucien Li
 
Essential oracle security internal for dba
Essential oracle security internal for dbaEssential oracle security internal for dba
Essential oracle security internal for dbamaclean liu
 
Mongo db部署架构之优先方案
Mongo db部署架构之优先方案Mongo db部署架构之优先方案
Mongo db部署架构之优先方案Lucien Li
 
Csdn Emag(Oracle)第二期
Csdn Emag(Oracle)第二期Csdn Emag(Oracle)第二期
Csdn Emag(Oracle)第二期yiditushe
 
Mysql 高级优化之 理解查询执行
Mysql 高级优化之 理解查询执行Mysql 高级优化之 理解查询执行
Mysql 高级优化之 理解查询执行nigel889
 
基于linux-HA 的PG高可用性
基于linux-HA 的PG高可用性基于linux-HA 的PG高可用性
基于linux-HA 的PG高可用性babyyellow li
 
人工智慧09_神經網路(TensorFlow+Keras)
人工智慧09_神經網路(TensorFlow+Keras)人工智慧09_神經網路(TensorFlow+Keras)
人工智慧09_神經網路(TensorFlow+Keras)Fuzhou University
 
分布式系统缓存设计
分布式系统缓存设计分布式系统缓存设计
分布式系统缓存设计zhujiadun
 
分布式系统缓存设计
分布式系统缓存设计分布式系统缓存设计
分布式系统缓存设计aleafs
 
Mysql 高级优化之 逻辑处理
Mysql 高级优化之 逻辑处理Mysql 高级优化之 逻辑处理
Mysql 高级优化之 逻辑处理nigel889
 
卷積神經網路(Python+TensorFlow+Keras)
卷積神經網路(Python+TensorFlow+Keras)卷積神經網路(Python+TensorFlow+Keras)
卷積神經網路(Python+TensorFlow+Keras)Fuzhou University
 
我对后端优化的一点想法 (2012)
我对后端优化的一点想法 (2012)我对后端优化的一点想法 (2012)
我对后端优化的一点想法 (2012)james tong
 
Mysql展示功能与源码对应
Mysql展示功能与源码对应Mysql展示功能与源码对应
Mysql展示功能与源码对应zhaolinjnu
 
Oracle10g高级安全特性列加密技术
Oracle10g高级安全特性列加密技术Oracle10g高级安全特性列加密技术
Oracle10g高级安全特性列加密技术maclean liu
 
【诗檀软件 郭兆伟-技术报告】跨国企业级Oracle数据库备份策略
【诗檀软件 郭兆伟-技术报告】跨国企业级Oracle数据库备份策略【诗檀软件 郭兆伟-技术报告】跨国企业级Oracle数据库备份策略
【诗檀软件 郭兆伟-技术报告】跨国企业级Oracle数据库备份策略maclean liu
 
Dog svr
Dog svrDog svr
Dog svryxcwf
 
dbdao.com 汪伟华 my-sql-replication复制高可用配置方案
dbdao.com 汪伟华 my-sql-replication复制高可用配置方案dbdao.com 汪伟华 my-sql-replication复制高可用配置方案
dbdao.com 汪伟华 my-sql-replication复制高可用配置方案maclean liu
 
Mysql handlersocket
Mysql handlersocketMysql handlersocket
Mysql handlersocketpwesh
 

What's hot (20)

Mysql introduction-and-performance-optimization
Mysql introduction-and-performance-optimizationMysql introduction-and-performance-optimization
Mysql introduction-and-performance-optimization
 
Mongo db部署架构之优先方案
Mongo db部署架构之优先方案Mongo db部署架构之优先方案
Mongo db部署架构之优先方案
 
Essential oracle security internal for dba
Essential oracle security internal for dbaEssential oracle security internal for dba
Essential oracle security internal for dba
 
Mongo db部署架构之优先方案
Mongo db部署架构之优先方案Mongo db部署架构之优先方案
Mongo db部署架构之优先方案
 
Csdn Emag(Oracle)第二期
Csdn Emag(Oracle)第二期Csdn Emag(Oracle)第二期
Csdn Emag(Oracle)第二期
 
Mysql 高级优化之 理解查询执行
Mysql 高级优化之 理解查询执行Mysql 高级优化之 理解查询执行
Mysql 高级优化之 理解查询执行
 
基于linux-HA 的PG高可用性
基于linux-HA 的PG高可用性基于linux-HA 的PG高可用性
基于linux-HA 的PG高可用性
 
人工智慧09_神經網路(TensorFlow+Keras)
人工智慧09_神經網路(TensorFlow+Keras)人工智慧09_神經網路(TensorFlow+Keras)
人工智慧09_神經網路(TensorFlow+Keras)
 
分布式系统缓存设计
分布式系统缓存设计分布式系统缓存设计
分布式系统缓存设计
 
分布式系统缓存设计
分布式系统缓存设计分布式系统缓存设计
分布式系统缓存设计
 
Mysql 高级优化之 逻辑处理
Mysql 高级优化之 逻辑处理Mysql 高级优化之 逻辑处理
Mysql 高级优化之 逻辑处理
 
卷積神經網路(Python+TensorFlow+Keras)
卷積神經網路(Python+TensorFlow+Keras)卷積神經網路(Python+TensorFlow+Keras)
卷積神經網路(Python+TensorFlow+Keras)
 
我对后端优化的一点想法 (2012)
我对后端优化的一点想法 (2012)我对后端优化的一点想法 (2012)
我对后端优化的一点想法 (2012)
 
Mysql展示功能与源码对应
Mysql展示功能与源码对应Mysql展示功能与源码对应
Mysql展示功能与源码对应
 
Optimzing mysql
Optimzing mysqlOptimzing mysql
Optimzing mysql
 
Oracle10g高级安全特性列加密技术
Oracle10g高级安全特性列加密技术Oracle10g高级安全特性列加密技术
Oracle10g高级安全特性列加密技术
 
【诗檀软件 郭兆伟-技术报告】跨国企业级Oracle数据库备份策略
【诗檀软件 郭兆伟-技术报告】跨国企业级Oracle数据库备份策略【诗檀软件 郭兆伟-技术报告】跨国企业级Oracle数据库备份策略
【诗檀软件 郭兆伟-技术报告】跨国企业级Oracle数据库备份策略
 
Dog svr
Dog svrDog svr
Dog svr
 
dbdao.com 汪伟华 my-sql-replication复制高可用配置方案
dbdao.com 汪伟华 my-sql-replication复制高可用配置方案dbdao.com 汪伟华 my-sql-replication复制高可用配置方案
dbdao.com 汪伟华 my-sql-replication复制高可用配置方案
 
Mysql handlersocket
Mysql handlersocketMysql handlersocket
Mysql handlersocket
 

Similar to 基于Innodb开发的最佳实践

探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG
探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG
探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUGYingSiang Geng
 
2011 06-12-lamp-mysql-顾春江
2011 06-12-lamp-mysql-顾春江2011 06-12-lamp-mysql-顾春江
2011 06-12-lamp-mysql-顾春江thinkinlamp
 
2011 06-12-lamp-mysql
2011 06-12-lamp-mysql2011 06-12-lamp-mysql
2011 06-12-lamp-mysqlpwesh
 
阿里巴巴 叶正盛 数据库性能量化
阿里巴巴 叶正盛 数据库性能量化阿里巴巴 叶正盛 数据库性能量化
阿里巴巴 叶正盛 数据库性能量化colderboy17
 
阿里巴巴 叶正盛 数据库性能量化
阿里巴巴 叶正盛 数据库性能量化阿里巴巴 叶正盛 数据库性能量化
阿里巴巴 叶正盛 数据库性能量化guiyingshenxia
 
MySQL 6.0 下的cluster + replicate - 20080220
MySQL 6.0 下的cluster + replicate - 20080220MySQL 6.0 下的cluster + replicate - 20080220
MySQL 6.0 下的cluster + replicate - 20080220Jinrong Ye
 
Continuous Delivery Workshop with Ansible x GitLab CI (2nd)
Continuous Delivery Workshop with Ansible x GitLab CI (2nd)Continuous Delivery Workshop with Ansible x GitLab CI (2nd)
Continuous Delivery Workshop with Ansible x GitLab CI (2nd)Chu-Siang Lai
 
Mysql遇到的一些问题
Mysql遇到的一些问题Mysql遇到的一些问题
Mysql遇到的一些问题wang tongchao
 
Osc scott linux下的数据库优化for_postgresql
Osc scott linux下的数据库优化for_postgresqlOsc scott linux下的数据库优化for_postgresql
Osc scott linux下的数据库优化for_postgresqlOpenSourceCamp
 
110824 knoss-windows系统机制浅析
110824 knoss-windows系统机制浅析110824 knoss-windows系统机制浅析
110824 knoss-windows系统机制浅析Zoom Quiet
 
数据库极限性能测试
数据库极限性能测试数据库极限性能测试
数据库极限性能测试helbreathszw
 
MongoDB at Qihoo 360
MongoDB at Qihoo 360MongoDB at Qihoo 360
MongoDB at Qihoo 360MongoDB
 
腾讯大讲堂06 qq邮箱性能优化
腾讯大讲堂06 qq邮箱性能优化腾讯大讲堂06 qq邮箱性能优化
腾讯大讲堂06 qq邮箱性能优化topgeek
 
淘宝数据魔方的系统架构 -长林
淘宝数据魔方的系统架构 -长林淘宝数据魔方的系统架构 -长林
淘宝数据魔方的系统架构 -长林Shaoning Pan
 
NoSQL误用和常见陷阱分析
NoSQL误用和常见陷阱分析NoSQL误用和常见陷阱分析
NoSQL误用和常见陷阱分析iammutex
 
腾讯大讲堂06 qq邮箱性能优化
腾讯大讲堂06 qq邮箱性能优化腾讯大讲堂06 qq邮箱性能优化
腾讯大讲堂06 qq邮箱性能优化areyouok
 
腾讯大讲堂06 qq邮箱性能优化
腾讯大讲堂06 qq邮箱性能优化腾讯大讲堂06 qq邮箱性能优化
腾讯大讲堂06 qq邮箱性能优化topgeek
 
Mysql fast share
Mysql fast shareMysql fast share
Mysql fast sharerfyiamcool
 
Avm2虚拟机浅析与as3性能优化(陈士凯)
Avm2虚拟机浅析与as3性能优化(陈士凯)Avm2虚拟机浅析与as3性能优化(陈士凯)
Avm2虚拟机浅析与as3性能优化(陈士凯)FLASH开发者交流会
 
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)Shanda innovation institute
 

Similar to 基于Innodb开发的最佳实践 (20)

探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG
探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG
探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG
 
2011 06-12-lamp-mysql-顾春江
2011 06-12-lamp-mysql-顾春江2011 06-12-lamp-mysql-顾春江
2011 06-12-lamp-mysql-顾春江
 
2011 06-12-lamp-mysql
2011 06-12-lamp-mysql2011 06-12-lamp-mysql
2011 06-12-lamp-mysql
 
阿里巴巴 叶正盛 数据库性能量化
阿里巴巴 叶正盛 数据库性能量化阿里巴巴 叶正盛 数据库性能量化
阿里巴巴 叶正盛 数据库性能量化
 
阿里巴巴 叶正盛 数据库性能量化
阿里巴巴 叶正盛 数据库性能量化阿里巴巴 叶正盛 数据库性能量化
阿里巴巴 叶正盛 数据库性能量化
 
MySQL 6.0 下的cluster + replicate - 20080220
MySQL 6.0 下的cluster + replicate - 20080220MySQL 6.0 下的cluster + replicate - 20080220
MySQL 6.0 下的cluster + replicate - 20080220
 
Continuous Delivery Workshop with Ansible x GitLab CI (2nd)
Continuous Delivery Workshop with Ansible x GitLab CI (2nd)Continuous Delivery Workshop with Ansible x GitLab CI (2nd)
Continuous Delivery Workshop with Ansible x GitLab CI (2nd)
 
Mysql遇到的一些问题
Mysql遇到的一些问题Mysql遇到的一些问题
Mysql遇到的一些问题
 
Osc scott linux下的数据库优化for_postgresql
Osc scott linux下的数据库优化for_postgresqlOsc scott linux下的数据库优化for_postgresql
Osc scott linux下的数据库优化for_postgresql
 
110824 knoss-windows系统机制浅析
110824 knoss-windows系统机制浅析110824 knoss-windows系统机制浅析
110824 knoss-windows系统机制浅析
 
数据库极限性能测试
数据库极限性能测试数据库极限性能测试
数据库极限性能测试
 
MongoDB at Qihoo 360
MongoDB at Qihoo 360MongoDB at Qihoo 360
MongoDB at Qihoo 360
 
腾讯大讲堂06 qq邮箱性能优化
腾讯大讲堂06 qq邮箱性能优化腾讯大讲堂06 qq邮箱性能优化
腾讯大讲堂06 qq邮箱性能优化
 
淘宝数据魔方的系统架构 -长林
淘宝数据魔方的系统架构 -长林淘宝数据魔方的系统架构 -长林
淘宝数据魔方的系统架构 -长林
 
NoSQL误用和常见陷阱分析
NoSQL误用和常见陷阱分析NoSQL误用和常见陷阱分析
NoSQL误用和常见陷阱分析
 
腾讯大讲堂06 qq邮箱性能优化
腾讯大讲堂06 qq邮箱性能优化腾讯大讲堂06 qq邮箱性能优化
腾讯大讲堂06 qq邮箱性能优化
 
腾讯大讲堂06 qq邮箱性能优化
腾讯大讲堂06 qq邮箱性能优化腾讯大讲堂06 qq邮箱性能优化
腾讯大讲堂06 qq邮箱性能优化
 
Mysql fast share
Mysql fast shareMysql fast share
Mysql fast share
 
Avm2虚拟机浅析与as3性能优化(陈士凯)
Avm2虚拟机浅析与as3性能优化(陈士凯)Avm2虚拟机浅析与as3性能优化(陈士凯)
Avm2虚拟机浅析与as3性能优化(陈士凯)
 
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
 

基于Innodb开发的最佳实践

  • 1. 基于Innodb开发最佳实践 新媒传信 吴炳锡
  • 2. About me 新媒传信(飞信) 新技术研发部 @吴炳锡 数据库架构师 职责: 数据库基础平台研发 面向公司各部门提供数据库技术支持 业余: 北京MySQL活动发起者
  • 3. 大纲 • 案例一:为什么 MySQL这么慢 – 案例一分析 – 讨论解决方案 – 总结经验及运用 • 案例二: 死锁 – 案例二 分析 – Innodb锁的类型识别 – 总结经验及运用 • 总结
  • 5. 案例一:为什么Insert这么慢 • 背景 向一个表进行insert数据,为啥一秒钟才能写入500条 (有可能更少) • 表结构: CREATE TABLE `t1_rnd` ( `id` int(10) unsigned NOT NULL , `c1` varchar(64) NOT NULL, `c2` varchar(255) DEFAULT NULL, `c3` int(10) unsigned DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; • 写入程序: 备注中
  • 6. 案例一:为什么insert这么慢 $i_end = (int) '999999999‘; $i_start = 1000000000; for ($i = $i_start; $i < $i_end; $i++) { $x = mt_rand(); $sql = "INSERT INTO t1_rnd VALUES($x, 'name_$x', 'desc_$x', $i)"; $res = $pdo->exec($sql); ... }
  • 7. 案例一:为什么insert这么慢 记数从:100000 开始 ok 101282 w, per: 1079 /s ok 100503 w, per: 12307 /s ok 101283 w, per: 1093 /s ok 100504 w, per: 13369 /s ok 101284 w, per: 836 /s ... ok 101285 w, per: 942 /s ok 100508 w, per: 14082 /s ok 101286 w, per: 1021 /s ok 101287 w, per: 1033 /s ok 100509 w, per: 11058 /s ok 101288 w, per: 816 /s ok 100510 w, per: 12853 /s ok 101289 w, per: 802 /s … ok 101290 w, per: 1040 /s ok 101201 w, per: 15592 /s ok 101291 w, per: 778 /s ok 101202 w, per: 11037 /s ok 101292 w, per: 776 /s ok 101203 w, per: 13454 /s ... ok 101204 w, per: 12482 /s ok 101360 w, per: 618 /s ok 101205 w, per: 7162 /s ok 101361 w, per: 611 /s ok 101362 w, per: 580 /s ok 101206 w, per: 6323 /s ok 101363 w, per: 593 /s ok 101207 w, per: 4655 /s ... ok 101208 w, per: 6212 /s ok 101372 w, per: 563 /s ok 101209 w, per: 3960 /s ok 101373 w, per: 554 /s ok 101210 w, per: 2559 /s ok 101374 w, per: 504 /s ok 101211 w, per: 2170 /s ok 101375 w, per: 547 /s ... ok 101376 w, per: 569 /s ...
  • 8. 案例一分析 • 查看基本情况 – mysql> select count(*) from t1_rnd; – +----------+ – | count(*) | – +----------+ – | 13719413 | – +----------+ – 1 row in set (12 min 14.59 sec) • 文件大小: – -rw-rw---- 1 mysql3306 mysql 8.5K 08-09 15:01 t1_rnd.frm – -rw-rw---- 1 mysql3306 mysql 1.4G 08-09 15:50 t1_rnd.ibd
  • 9. 案例一分析 • 查看基本情况: – 通过Percona-Server的慢日值功能可以查看一下count有多少个 page被读到,读了多少行。 – mysql>set global log_slow_verbosity=full; – mysql>select count(*) from t1_rnd; 查看慢日值
  • 10. 慢日值内容: # Thread_id: 36 Schema: wubx Last_errno: 0 Killed: 0 # Query_time: 719.255557 Lock_time: 0.000051 Rows_sent: 1 Rows_examined: 13719413 Rows_affected: 0 Rows_read: 18446744073693256119 # Bytes_sent: 70 Tmp_tables: 0 Tmp_disk_tables: 0 Tmp_table_sizes: 0 # InnoDB_trx_id: 4A0B331 # QC_Hit: No Full_scan: Yes Full_join: No Tmp_table: No Tmp_table_on_disk: No # Filesort: No Filesort_on_disk: No Merge_passes: 0 # InnoDB_IO_r_ops: 74732 InnoDB_IO_r_bytes: 1224409088 InnoDB_IO_r_wait: 713.597767 # InnoDB_rec_lock_wait: 0.000000 InnoDB_queue_wait: 0.000000 # InnoDB_pages_distinct: 65254 SET timestamp=1312882181; select count(*) from t1_rnd;
  • 11. • 基本分析: mysql> select 65254*16/1024; – +---------------+ – | 65254*16/1024 | – +---------------+ – | 1019.5938 | – +---------------+ 计算一下数据大小: – mysql> select (4+30+30+4)*13719413/1024/1024; – +--------------------------------+ – | (4+4+30+30)*13719413/1024/1024 | – +--------------------------------+ – | 889.70192337 | – +--------------------------------+
  • 12. 案例一分析 • 思考问题: – 为什么我们计算需要存储该表的大小和实质物 理大小相差那么大呢? • 是索引增加了文件大小? – 为什么count那么慢,Rows_read: 18446744073693256119 !!!!
  • 13. 案例一分析 • 分析归纳: 文件大小超过计算: • 碎片产生的原因是Innodb表数据本身及索引都属 于btree结构。 • Innodb表按主建有序的存放(Cluster Index)
  • 14. 案例一分析 • Count统计太慢: • Innodb本身没这方计数器,如果进行无条件 的count实质上相当于把表的btree page全部 读取一次。 • 对于本身碎片很严重的表,这种全表扫描会 被成一很严重的随机IO操作 • 那个Read_Rows很大数据,从实质上理解 是错误的,这就是Bug.
  • 15. • 从测试数据来看在写入1200万前,性能还能接 受。 • 是不是可以考虑对于大表进行拆表处理? • 如果该表存在range类的操作,拆表是不是最佳的 方式呢? • 对于有碎片明显的表,如何处理能让快点呢? • 对于无条件count innodb做了什么?
  • 16. 讨论解决方案 看看表碎片比较少的情况的操作: • 对现存的表碎片整理的操作: mysql> alter table theme_irnd engine=Innodb; Query OK, 13719413 rows affected (34 min 48.24 sec) • 整理后文件大小: -rw-rw---- 1 mysql3306 mysql 848M 08-09 18:23 theme.ibd mysql> select count(*) from theme; +----------+ | count(*) | +----------+ | 13719413 | +----------+ 1 row in set (4.92 sec) • 如针对range操作,这样是不是已很好了
  • 17. • 针对range的在加速: mysql> create index idx_c3 on t1_rnd(c3); Query OK, 0 rows affected (44.37 sec) mysql> select count(*) from t1_rnd; +----------+ | count(*) | +----------+ | 13719413 | +----------+ 1 row in set (1.84 sec) • 什么情况,从原来的 12 min 14.59 sec->4.92 sec->1.84 sec?
  • 18. 讨论解决方案 • 对于无条件count innodb做了什么? 添加完idx_c3索引后: # Thread_id: 44 Schema: wubx Last_errno: 0 Killed: 0 # Query_time: 1.841461 Lock_time: 0.000051 Rows_sent: 1 Rows_examined: 13719413 Rows_affected: 0 Rows_read: 13719413 # Bytes_sent: 70 Tmp_tables: 0 Tmp_disk_tables: 0 Tmp_table_sizes: 0 # InnoDB_trx_id: 4A0B89B # QC_Hit: No Full_scan: Yes Full_join: No Tmp_table: No Tmp_table_on_disk: No # Filesort: No Filesort_on_disk: No Merge_passes: 0 # InnoDB_IO_r_ops: 0 InnoDB_IO_r_bytes: 0 InnoDB_IO_r_wait: 0.000000 # InnoDB_rec_lock_wait: 0.000000 InnoDB_queue_wait: 0.000000 # InnoDB_pages_distinct: 12252 SET timestamp=1312970168; select count(*) from t1_rnd; • 为什么用普通索引进行的count比PK快呢?
  • 19. 总结经验及运用 • 总结: – 在写入数据时保证主建是有顺的从小到大的方 式写入 – 对于Innodb要求快速写入的表添加一列自增的 自建做为索引 – 对于Innodb表的使用要保持一个好的习惯,尽 量基于唯一索引去访问数据(排除range) – 如果对于Innodb有大量的update操作,同时又 有大量的range操作,请考虑定期进行整理碎 片
  • 20. 总结经验及运用 • 验证: 同样的表结构,在写入程序做以下调整: for ($i = $i_start; $i < $i_end; $i++) { $x = $i; $sql = "INSERT INTO t1_rnd VALUES($x, 'name_$x', 'desc_$x', $i)"; $res = $pdo->exec($sql); ... }
  • 21. 总结经验及运用 计数:100000W开始 ... ok 100498 w, per: 21769 /s ok 102991 w, per: 21515 /s ok 100499 w, per: 21384 /s ok 100500 w, per: 21770 /s ok 102992 w, per: 21772 /s ok 100501 w, per: 21376 /s ok 102993 w, per: 18120 /s ok 100502 w, per: 21749 /s ok 102994 w, per: 19615 /s ... ok 102995 w, per: 21163 /s ok 101380 w, per: 21624 /s ok 102996 w, per: 21782 /s ok 101381 w, per: 21329 /s ok 102997 w, per: 21377 /s ok 101382 w, per: 21632 /s ok 101383 w, per: 21592 /s ok 102998 w, per: 21705 /s ok 101384 w, per: 21377 /s ok 102999 w, per: 13881 /s ok 101385 w, per: 18434 /s ok 103000 w, per: 20969 /s ok 101386 w, per: 19711 /s ... ... 写入到3000W行数据性能也很好
  • 22. 总结经验及运用 • 物理文件大小: • -rw-rw---- 1 mysql3306 mysql 8.5K 08-09 15:50 theme.frm • -rw-rw---- 1 mysql3306 mysql 1.9G 08-09 16:19 theme.ibd
  • 23. 总结经验及运用 • 运用思考下面类型的表如何设计: – 用户表(User)的设计 – 好友关系表 – LOG类型的表
  • 24. 总结经验及运用 • 进阶思考: – Update会给表带来分页操作吗? – Delete会对PAGE有影响吗? • 如何优化UPDATE&DELETE
  • 26. 案例二:死锁 • 背景: 利用show engine innodb statusG; 查看LATEST DETECTED DEADLOCK部分经常有死锁现象 死锁语句: DELETE FROM GRP_OfflineNotify WHERE UserId = 852577338 AND GroupId = 33990861 AND NotifyType = 10 DELETE FROM GRP_OfflineNotify WHERE UserId = 825749088 AND GroupId = 33990861 AND NotifyType = 10
  • 27. 案例二 分析 • 了解LATEST DETECTED DEADLOCK : >show engine innodb statusG; LATEST DETECTED DEADLOCK ------------------------ 这个死锁信息发生的时间 *** (N) TRANSACTION: 死锁的语句及相关的信息 *** (N) WAITING FOR THIS LOCK TO BE GRANTED: 死锁的原因
  • 28. 案例二 分析 • 死锁原因分析: mysql> explain select * from GRP_OfflineNotify where UserId=852577338 and GroupId=33990861 and NotifyType=10G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: GRP_OfflineNotify type: ref possible_keys: IX_GRP_OfflineNotify_GroupId_NotifyType,IX_GRP_OfflineNotify_UserId key: IX_GRP_OfflineNotify_GroupId_NotifyType key_len: 5 ref: const,const rows: 1 IX_GRP_OfflineNotify_Group Extra: Using where Id_NotifyType 1 row in set (0.00 sec) (GroupId, NotifyType) 普通索引
  • 29. 案例二 分析 • 原因归纳: 利用 IX_GRP_OfflineNotify_GroupId_NotifyType索引 去访问数据,而这个索引并不唯一,所以造成了 锁的区间较大,造成两个事务相互冲突死锁。 另外: 也可以参考show engine innodb statusG;中的 死锁部分中: WAITING FOR THIS LOCK TO BE GRANTED
  • 30. 案例二 分析 • 再回到问题上思考: 这个SQL是做什么的? 需要锁这么大的区间吗? • 死锁语句: DELETE FROM GRP_OfflineNotify WHERE UserId = 852577338 AND GroupId = 33990861 AND NotifyType = 10 DELETE FROM GRP_OfflineNotify WHERE UserId = 825749088 AND GroupId = 33990861 AND NotifyType = 10
  • 31. 案例二 分析 • 非唯一索引Delete死锁原因: root brach1 5: col2= 3399086 ,col3=10,… Leaf 1 Sec Ind1 PK loc 1001:col2= 3399086 ,col3=10,… k 3399086 10 5 X 1006:col2= 3399086 ,col3=10,… 3399086 10 1001 X 3399086 10 1006 X Table Redords … 96257735 11 2 6
  • 32. • 解决办法: – 创建新索引: create index IX_GRP_OfflineNotify_GroupId _UserId_NotifyType on GRP_OfflineNotify(Grou pId,UserId,NotifyType); – 删除旧索引: drop index IX_GRP_OfflineNotify_GroupId_ NotifyType on GRP_OfflineNotify;
  • 33. • Innodb支持的锁类型: – Record lock – Next Key lock – Gap lock – Table lock • 高并环境事务隔离级别: READ-COMMITTED
  • 34. Innodb锁的类型识别 • Gap-lock – 这个锁影响Insert操作。 假设一个索引包括5,7利用这个索引访问过的 取出结果为5,7相关记录,但同时别的 session需要insert一个索引为6的索引,这个就 需要等待。 该锁在:READ-COMMITTED隔离级别下不工作。 • Table-lock 属于显式声明的,可以忽略。
  • 35. 总结经验及运用 • Innodb索引分情况: root root brach1 brach1 Leaf 1 Leaf 1 Sec Ind1 PK Pk Table other recoder 1 5 1 col2=‘wubx’, col3=‘775’,… 5 1 2 col2=‘liuxin’,col3=‘123’,… … … 99 2 5 Col2=‘zbr’,col3=‘1000’… Select * from tb where sec_ind1=1
  • 36. 总结经验及运用 • 变长字段处理: … Prefix(768B) … COMACT OverFlow page 20 bytes … … DYNAMIC OverFlow page
  • 37. 总结经验及运用 • 讨论个问题: – 为什么Innodb表设计中有条:没有特殊的理由 请给该表添加一个自增的例做主建? – 那么有特属的理由又是啥呢?
  • 38. 总结经验及运用 • 运用: – 养成基于唯一索引访问数据的习惯 – Update操作不要去update主建 – 没有特殊的理由请给你的表添加一个无符号自 增列做为主建 – 如果大量的查询是基于条件的range操作,请把 这个索引做为第二索引