InnoDB表优化

InnoDB表存储优化

  • 适时的使用 OPTIMIZE TABLE 语句来重组表,压缩浪费的表空间。这是在其它优化技术不可用的情况下最直接的方法。

OPTIMIZE TABLE 语句通过拷贝表数据并重建表索引,使得索引数据更加紧凑,减少空间碎片。语句的执行效果会因表的不同而不同。过大的表或者过大的索引及初次添加大量数据的情况下都会使得这一操作变慢。

  • InnoDB表,如果主键过长(长数据列做主键,或者多个列组合做主键)会浪费很多空间。同时,二级索引也包含主键。这种情况,可以考虑创建自增列作为主键,或者使用前缀索引。
  • 对于需要存储长度不定或者包含很多NULL值的字符串列,使用 VARCHAR 代替 CHAR 。在小表应用上,缓存使用及磁盘I/O消耗会更小。
  • 对于包含大量重复文本或者数字的大表,可以考虑采用压缩的行格式存储。这样数据加载会减少对缓存及I/O的需求。在使用压缩行格式前,需要考虑压缩行格式 COMPRESSED 和的不同性能影响。

InnoDB 事务管理优化

优化InnoDB 事务处理,主要需要找到事务特性和服务器负载间的某个平衡点。例如,一秒需要提交几千事务的,或者每隔2-3个小时提交一次事务的不同应用表现。

  • MySQL的默认设置AUTOCOMMIT=1 会限制繁忙数据库的性能。如果可以的话,可以在应用中使用SET AUTOCOMMIT=0 或者 START TRANSACTION ,然后将多个相关的数据变更操作添加到同一事务中,然后执行COMMIT 语句来提交事务,提交数据变更。

InnoDB 对于引发数据库变更的操作,必须将其进行日志刷盘。

  • 对于只包含SELECT 语句的事务,启用 AUTOCOMMIT ,使得 InnoDB 能够识别只读事务,然后进行相应的优化。
  • 避免对大数据量操作插入,更新和删除之后的回滚操作。如果一个大的事务拖慢了服务器,那么回滚将是服务器性能变得更糟。可以分批处理大数据量操作。通过杀进程方式终止的回滚操作会在服务器启动时重新启动。

可以通过如下策略减少此类问题发生:

  • 增大缓存,避免频繁磁盘I/O。
  • 设置 innodb_change_buffering=all,这样update和delete操作也会和insert一样进行缓存,回滚也更快。
  • 手动commit,分割大数据操作。

为了避免时空的回滚。增大缓存,使得回滚进程可以应用到最大的资源以便快速执行。或者杀掉回滚进程,然后使用innodb_force_recovery=3选项重启。

对于较多执行耗时inserts, updates, 及deletes 操作的服务器,确保innodb_change_buffering=all开启。

  • InnoDB 如会每秒刷盘一次日志,如果可以承受最新事务崩溃的数据损失,可以设置innodb_flush_log_at_trx_commit = 0。虽然日志的刷盘操作也不是保证的,同时也可以设置innodb_support_xa = 0,减少磁盘和二进制日志的同步操作。

Note

innodb_support_xa 已被弃用,将来版本会被移除。MySQL 5.7.10版本,InnoDB  XA事务的两阶段提交是默认支持的,不能设置禁用innodb_support_xa

  • 行修改或删除后,行数据及undo logs在物理上并没有立刻被变更。即使在事务立刻提交后。旧数据会保持直到之前启动的事务或者并发执行的事务完成后。这样,这些食物可以一直访问到相关的旧数据。所以耗时的事务会阻止 InnoDB 清除其它相关事务的数据。
  • 如果一个耗时的事务修改或者删除了某些行。那么其它使用这些数据的事务,如果事务级别设置在READ COMMITTED 作者 REPEATABLE READ 级别,则需要额外的处理来重建旧数据。
  • 当一个耗时的事务修改了某个表,其它使用此表的事务将不会使用覆盖索引。如果二级索引包含比较新的PAGE_MAX_TRX_ID,或者某些记录被标记为已删除,InnoDB 可能需要使用聚簇索引来查询相应的记录。

覆盖索引查询(使用二级索引即可获得所需的数据,而不需要访问表数据)

InnoDB只读事务优化

InnoDB 可以避免给只读事务赋transaction ID (TRX_ID )。事务ID只对执行写操作,或者含锁读操作,如 SELECT ... FOR UPDATE有用。去除不必要的事务ID,有助于减少每次读写操作必须访问的内部数据结构大小。

InnoDB 在一下情景能够识别只读操作:

  • 事务以语句 START TRANSACTION READ ONLY 开始,这种情况下,数据变更操作会引发错误,事务仍会以只读性质运行:
ERROR 1792 (25006): Cannot execute statement in a READ ONLY transaction.

对于事务中的临时表可以进行任何操作。

  • autocommit = on,并且事务只包含一个语句,且语句为没有使用FOR UPDATE 或者 LOCK IN SHARED MODE 的SELECT 语句。
  • 事务以READ ONLY 选项开始。

这样,对于读繁忙的应用,如报表应用,可以将一系列的查询语句综合到一个只读的事务中,或者在执行查询前设置 autocommit = on,或者在应用中避免将变更操作和查询操作相互影响。.

重做日志(redo log)优化

可以考虑遵循以下优化指引:

  • 确保重做日志足够大,即使和缓存池(buffer pool)一样大。当 InnoDB 写满redo log时,服务器会基于一个检查点(checkpoint)就会将日志中的变更内容写到磁盘。如果redo log 文件过小,那么就会引发服务器频繁的写盘。虽然之前,设置过大的redo log 会引起恢复时间的过长,但是现在,恢复机制已经在速度上有很大的优化,因此不用再考虑此因素。

The size and number of redo log 文件的大小和数量可以使用: innodb_log_file_size 和 innodb_log_files_in_group 进行设置。

  • 可以考虑增大日志缓存(log buffer)。大的日志缓存可以容纳更大的事务执行,避免不必要的写盘操作。设置变量:innodb_log_buffer_size 。
  • 配置innodb_log_write_ahead_size 变量以避免 “read-on-write”(就是当修改的字节不足一个洗系统block时,需要将整个block读进内存,修改对应的位置,然后再写进去;如果我们以block为单位来写入的话,直接完整覆盖写入即可)。这个配置定义了redo log的write-ahead块大小。设置innodb_log_write_ahead_size 的大小以匹配操作系统或者文件系统的缓存块大小。Read-on-write 的产生是因为在write-ahead 块大小和操作系统或者文件系统的缓存块大小不匹配的情况下,redo log 块无法完全的写入到操作系统,或者文件系统引起的。

innodb_log_write_ahead_size 的值可以设置为InnoDB 日志文件块大小的倍数(2n)。最小的值为(512)。设置为最小值时Write-ahead不会发生。最大值为innodb_page_size 。如果设置的值大于innodb_page_size,那么服务器会使用innodb_page_size值。

innodb_log_write_ahead_size 值设置的太小,会导致read-on-write;设置过大,则会影响fsync 性能,因为一次需要些多个数据块。

InnoDB表的大数据载入

快速插入通用指引:

  • 导入数据时,关闭autocommit 模式,避免每次行插入导致的日志刷盘。在执行开始及结束使用SET autocommit 及 COMMIT 语句:
SET autocommit=0;
...SQLimport statements ...
COMMIT;

mysqldump 选项 --opt (默认启用)会创建dump转储 文件,以执行快速数据导入,避免将所有的数据载入内存引发问题。即使不使用SET autocommit 和 COMMIT

  • 如果在二级索引键上有 UNIQUE 限制,可以在载入时暂时关闭比检查:
SET unique_checks=0;
...SQLimport statements ...
SET unique_checks=1;

对于较大的表,此操作可以节省大量的磁盘I/O,因为InnoDB 可以使用它的 change buffer(change buffer的主要目的是将对二级索引的数据操作缓存下来,以此减少二级索引的随机IO,并达到操作合并的效果)来批量写二级索引记录。确保数据不包含重复键。

  • 如果表键包含FOREIGN KEY 限制。可以再导入期间关闭此限制:
  • 使用批量多行插入,以减少不必要客户端服务器间通信:
SET foreign_key_checks=0;
...SQLimport statements ...
SET foreign_key_checks=1;
INSERT INTO yourtable VALUES (1,2), (5,5), ...;

适用于任何类型表。

  • 当批量插入涉及自增列时,设置 innodb_autoinc_lock_mode = 2 (默认1,0:traditional;1:consecutive;2:interleaved)。
  • 以主键的顺序进行批量插入会更快。InnoDB 表主键索引未聚簇索引(clustered index, 以主键的顺序访问会很快)。特别是对于无法完全载入缓存的大表。
  • 全文索引导入:
  1. 表创建时定义新列FTS_DOC_ID类型BIGINT UNSIGNED NOT NULL,,列上定义索引FTS_DOC_ID_INDEX,如下:
  2. 载入数据。
  3. 数据载入后,在相应的列上创建全文索引。
CREATE TABLE t1 (
FTS_DOC_ID BIGINT unsigned NOT NULL AUTO_INCREMENT,
title varchar(255) NOT NULL DEFAULT ‘‘,
text mediumtext NOT NULL,
PRIMARY KEY (`FTS_DOC_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE UNIQUE INDEX FTS_DOC_ID_INDEX on t1(FTS_DOC_ID);

Note

在innodb存储引擎中,为了支持全文检索,必须有一个列与word进行映射,在innodb中这个列被命名为FTS_DOC_ID,其类型必须为BIGINT UNSIGNED NOT NULL,并且innodb存储引擎会在该列上加上一个名为FTS_DOC_ID_INDEX的唯一索引。上述操作由innodb存储引擎自己完成,用户也可以在创建表时手动添加,主要对应的约束条件。

常规的索引是文档到关键词的映射:文档——>关键词
倒排索引是关键词到文档的映射:关键词——>文档
全文索引通过关键字找到关键字所在文档,可以提高查询效率

表创建时添加FTS_DOC_ID 列,确保FTS_DOC_ID 列跟随全文索引列同步更新(FTS_DOC_ID 必须随着相应的 INSERT 或者 UPDATE变更单调递增)。如果不添加FTS_DOC_ID 列,而让InnoDB 来管理DOC IDs,InnoDB 也会在执行CREATE FULLTEXT INDEX时添加隐藏列FTS_DOC_ID 。这样,则需要进行额外的表重建过程,造成不必要的性能影响。

InnoDB查询优化

创建适当的索引以优化查询,通用指引如下:

  • 将关键查询最常用的的列包含近表主键中。
  • 主键列不要使用过多的列或者过长的列。因为二级索引包含主键,过大的主键会造成磁盘I/O及内存的浪费。
  • 不要在每个列上创建二级索引,一个查询只能使用一个索引。对于极少使用的列及列选择性不大的列创建索引对于查询优化不会有太大帮助。如果针对一个表的查询非常多,则需要找到能够有助于最多查询的多列主键。如果索引列能够覆盖所需要查询的数据列,那么就可以只使用索引进行数据查询,而不需要从表中获取数据。
  • 如果某一列的数据不能为NULL,那么在创建表的时候将其生命为 NOT
    NULL
     。优化器以此可以更高的决定最优使用索引。
  • 可以针对但查询事务进行相应的优化。

InnoDB DDL操作优化

  • 许多DDL操作,如表和索引的(CREATEALTER,
    DROP 语句) 可以在线之行。
  • 使用 TRUNCATE
    TABLE
     代替DELETE FROM tbl_name来清空表,外键限制可以使得TRUNCATE 语句如普通的DELETE 语句般操作。这种情景下,一系列如DROP
    TABLE
     及 CREATE
    TABLE
     语句会执行的很快。
  • 因为主键InnoDB表的存储结构是高度整合的,主键的变更会引起整张表的重构。最好将逐渐定义包含在表创建语句中,避免不必要的后期更改。

InnoDB磁盘I/O优化

如果数据库的设计及sql操作优化都遵循了最佳实践,数据库依然因为I/O负载而反应非常慢,那么就需要针对I/O进行专门的优化。可以通过Unix 的top 工具,或者Windows
的任务管理器来查看工作负载,如果低于70%,那么负载则主要在磁盘。

  • 增大缓存:

InnoDB 缓存中的数据访问不需要磁盘I/O,使用innodb_buffer_pool_size 设置。建议设置为系统内存的50 ~ 75%。

  • 调整刷盘策略:

某些版本GNU/Linux 系统,使用fsync() 或者相关方法进行刷盘时,速度会非常慢。这时,如果影响到数据库性能,那么可以通过设置innodb_flush_method = O_DSYNC来变更刷盘策略。

  • 调整Linux系统AIO磁盘调度策略为noop(单队列) 或者deadline(读、写队列):cfg(公平队列,比较复杂):

InnoDB 在Linux系统上使用异步I/O 子系统(本地AIO)通过预读和写请求来执行数据文件读写。配置变量innodb_use_native_aio 默认启用。磁盘调度策略对本地
AIO印象比较大。通常建议设置为noop
或者
deadline。

  • Solaris 10 x86_64架构建议使用direct
    I/O策略:
  • RAID配置。
  • non-rotational 存储:

Non-rotational 存储适用于随机读写;rotational存储相反适用于顺序读写。不同的存储设备对数据及日志的操作类型不同。

数据库随机读写类文件包括:file-per-table 和general tablespace数据文件, undo tablespace文件和temporary tablespace 文件。顺序读写类文件包括:InnoDB system tablespace 文件(基于 doublewrite buffering and change buffering) 及日志文件( binary log 文件和redo log 文件等)。

使用non-rotational
存储时,需要对一下配置进行优化:

crc32 算法使用了一种更快的一致性检查算法,对于高速存储设备,推荐使用。

针对rotational存储设备优化。对于non-rotational设备或者混用情景,则需禁用。

默认的200设定对于低端non-rotational存储设备已经足够。其它,酌情设置。

默认2000
针对non-rotational
存储。

如果redo logs存储在non-rotational设备,可以开率禁用词选项来减少日志。

如果redo
logs 存储在non-rotational
存储设备,设置此选项最大读写缓存。

设置此值以匹配磁盘internal sector size。早期的SSD设备为4KB,一些新版本的SSD能够支持到16KB。默认的额InnoDB 也大小为16KB。尽量是的数据库也大小和存储设备的块大小接近,减少无法一次写入磁盘的数据大小。

binary
logs 存储在non-rotational
设备情况下,如果所有的表都有主键,那么可以将此变量设置为最小来减少日志。

Ensure that TRIM support is
enabled for your operating system. It is typically enabled by default.

  • 增大I/O容量以减少backlogs负载:

如果吞吐量会因为检测点操作而不间断的降低,那么可以开率增加 innodb_io_capacity 的值。值越大,数据库刷盘频率会增大,从而避免了因为backlog的操作带来的吞吐量的影响。

  • 调整数据库I/O容量。

如果系统能够满足nnoDB 刷盘操作。可以考虑减小innodb_io_capacity 配置。通常需要将此变量尽量设置低一些。(SHOW
ENGINE INNODB STATUS

  • 将系统表空间文件存储在Fusion-io(做存储系统的公司) 设备。

如果使用支持原子写的Fusion-io设备存储系统表空间文件(“ibdata files”)
,那么可以对doublewrite
buffer-related I/O进行相应的优化。这种情况下,会自动使用Fusion-io设备的原子写替代doublewrite
buffering (innodb_doublewrite)进行数据的读写。这种特性只支持Fusion-io硬件设备及Fusion-io
NVMFS Linux应用。可以通过变量innodb_flush_method =
O_DIRECT 进行配置。

Note

设置是全局性的,影响所有设备上的数据读写。

  • 禁用压缩数据页日志:

使用 InnoDB 表压缩特性时,重新压缩的图片数据页,如果数据有变化,则会写入redo log。配置变量innodb_log_compressed_pages默认启用,防止数据库恢复期间,因为zlib算法的变化引发数据库崩溃。如果可以确认zlib版本不会发生变化,那么可以关闭innodb_log_compressed_pages 变量来减少重压缩产生的redo
log 负载。

原文地址:https://www.cnblogs.com/niejunlei/p/10320303.html

时间: 2024-11-09 00:41:11

InnoDB表优化的相关文章

Innodb IO优化 — 数据库表设计 转

数据库表设计这块学问比较多,我这里单从互联网角度出发同时结合Innodb的特性给出一些设计方法供大家参考.本文构建大概分两分部分:Innodb的特性及设计中如何利用这种特性. Innodb特性: Innodb是索引聚集表, 存储结构是BTREE Innodb的表的数据存储是有顺序的,默认是以主建排序,主建即是数据本身,不单独存放. 如果没有主建,Innodb以第一个唯一索引排序,如果连唯一索引也没,Innodb内部会产生一个6字节的字段排序(这个也是性能杀手,所以对这块如果不想花太多时间去想这个

详解MySQL大表优化方案

当MySQL单表记录数过大时,增删改查性能都会急剧下降,可以参考以下步骤来优化: 单表优化 除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分,拆分会带来逻辑.部署.运维的各种复杂度,一般以整型值为主的表在千万级以下,字符串为主的表在五百万以下是没有太大问题的.而事实上很多时候MySQL单表的性能依然有不少优化空间,甚至能正常支撑千万级以上的数据量: 字段 尽量使用TINYINT.SMALLINT.MEDIUM_INT作为整数类型而非INT,如果非负则加上UNSIGNED VARCHAR的

针对MySQL大表优化方案

详解MySQL大表优化方案 (1).字段 (2).索引 (3).规范查询SQL (4).存储引擎 (5).mysql配置参数优化 (6).mysql读写分离 (7).分区和分表 单表优化: 当单表的数据不是一直在暴增,不建议使用拆分,拆分会带来逻辑,部署,运维的各种复杂度,一般以整型值为主的表在千万级以下,字符串为主的表在五百万以下是没有太大问题的.而事实上很多时候MySQL单表的性能依然有不少优化空间,甚至能正常支撑千万级以上的数据量 (1).字段 l 尽量使用TINYINT.SMALLINT

小贝_mysql表优化

mysql表优化 简要:        一.分析表 二.检查表 三.优化表 四.表数据导入 五.锁表操作 一.分析表 1.1.命令: ANALYZE [NO_WRITE_TO_BINLOG | LOCAL]TABLE tbl_name [, tbl_name] ... 1.2.作用: 本语句用于分析和存储表的keyword分布.分析的结果将可以使得系统得到准确的统计信息,使得sql可以生成正确的行计划 1.3.不足: 在分析期间,会对表进行读锁操作 1.4.样例: 二.检查表 2.1.命令 CH

MySQL 大表优化方案探讨

当MySQL单表记录数过大时,增删改查性能都会急剧下降,可以参考以下步骤来优化: 单表优化 除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分,拆分会带来逻辑.部署.运维的各种复杂度,一般以整型值为主的表在千万级以下,字符串为主的表在五百万以下是没有太大问题的.而事实上很多时候MySQL单表的性能依然有不少优化空间,甚至能正常支撑千万级以上的数据量: 字段 尽量使用TINYINT.SMALLINT.MEDIUM_INT作为整数类型而非INT,如果非负则加上UNSIGNED VARCHAR的

mysql innodb 性能优化

默认情况下,innodb的参数设置的非常小,在生产环境中远远不够用比如最重要的两个参数innodb_buffer_pool_size 默认是8Minnodb_flush_logs_at_trx_commit 默认设置的是1 也就是同步刷新log(可以这么理解) innodb_buffer_pool_size: 这是InnoDB最重要的设置,对InnoDB性能有决定性的影响.默认的设置只有8M,所以默认的数据库设置下面InnoDB性能很差.在只有 InnoDB存储引擎的数据库服务器上面,可以设置6

MySQL大表优化方案总结

今天看了一篇mysql大表优化方案的文章( https://mp.weixin.qq.com/s/qM6MAd_ZcrHEapz0D4nSrA ),应该说是属于科普级别的,但是技术肯定是要先大概理解了才能再深入的,深入的话推荐看 MySQL技术内幕:InnoDB存储引擎(第2版) 总结一下大表的优化方案就是: 分库分表加分区 各个层级加缓存(mysql层是缓存调参) 字段索引要优化 SQL语句别复杂 读写分离大法好 升级硬件是王道

Mysql Innodb 引擎优化

介绍: InnoDB给MySQL提供了具有提交,回滚和崩溃恢复能力的事务安全(ACID兼容)存储引擎.InnoDB锁定在行级并且也在SELECT语句 提供一个Oracle风格一致的非锁定读.这些特色增加了多用户部署和性能.没有在InnoDB中扩大锁定的需要,因为在InnoDB中行级锁定适合非常 小的空间.InnoDB也支持FOREIGN KEY强制.在SQL查询中,你可以自由地将InnoDB类型的表与其它MySQL的表的类型混合起来,甚至在同一个查询中也可以混合. Innodb 的创始人:Hei

关于MySQL InnoDB表的二级索引是否加入主键列的问题解释

关于MySQL InnoDB表的二级索引是否加入主键,总结如下: 1对于MySQL InnoDB表的二级索引是否加入主键,官方也有明确的说明,建议线上MySQL的二级索引创建时强制加入主键所有的列,可以做到所有的MySQL 版本统一. 2.MySQL 5.6.9之前,InnoDB引擎层是会对二级索引做自动扩展,但是优化器不能识别出扩展的主键. 3.MySQL 5.6.9开始InnoDB引擎层是会对二级索引做自动扩展,优化器能识别出扩展的主键. 4.索引的大小一样,二级索引有没有加入主键列,在In