zoukankan      html  css  js  c++  java
  • mysql优化———第二篇:数据库优化调整参数

    摘要

    参数调优内容:
      1. 内存利用方面
      2. 日志控制方面
      3.文件IO分配,空间占用方面
      4. 其它相关参数


    一  摘要

    通过参数提高MYSQL的性能。核心思想如下:
            1 提高mysql内存大小。
              这是最重要的参数。增大MYSQL内存可以把操作都在内存中执行。Innodb的缓冲池会缓存数据和索引,所以不需要给系统的缓存留空间,如果只用Innodb,可以把这个值设为内存的70%-80%。  修改配置文件或者参数innodb_buffer_pool_size
    2  提高写日志的性能。
        (1)将 innodb_flush_log_at_trx_commit 配置设定为0;减少写日志的频率。
        (2)  innodb_log_buffer_size 增大。 增大日志缓存,减少写数据文件次数。
       
        (3)   innodb_log_file_size     增大。 
        (4)  sync_binlog =  N  提高日志写入磁盘速率  可设置为很大,比如2000,看具体场景

    N>0  — 每向二进制日志文件写入N条SQL或N个事务后,则把二进制日志文件的数据刷新到磁盘上;

    N=0  — 不主动刷新二进制日志文件的数据到磁盘上,而是由操作系统决定;

     3 提高写数据的性能
        (1)将 innodb_autoextend_increment 增大。减少表空间扩展次数
    4 其他可调参数
    (1)   innodb_flush_method             = O_DIRECT  
    innodb_flush_method这个参数控制着innodb数据文件及redo log的打开、刷写模式,对于这个参数,文档上是这样描述的:
    有三个值:fdatasync(默认),O_DSYNC,O_DIRECT

     参考: http://blog.csdn.net/dukope/article/details/9015539
    (2)   事务隔离模式      
    transaction-isolation = 
    READ-UNCOMMITTED
    (3)读写线程数目可以增大
    innodb_read_io_threads = 8 innodb_write_io_threads = 4 











    1. 内存利用方面
    (1)innodb_buffer_pool_size  .    
             这个参数主要缓存innodb表的索引,数据,插入数据时的缓冲。为Innodb加速优化首要参数。
            最重要的参数,设为内存的70%-80%。
    2. 日志控制方面
    (1)innodb_log_file_size
                   参考自:计算日志大小
                   日志大小。增大日志文件大小,可以减少数据库checkpoint操作。
                  大小必须小于4G,不过设置多个,innodb_log_files_in_group  =2 ,默认是2。
                  估算大小的原则;innodb_log_file_size×2大小等于一个小时的数据写入量就可以了。也就是说一个小时触发一次checkpoint。这是一个经验值,当然越大越好,但是很大的情况不一定带来性能大的提升。
                  估算大小的方法:
    mysql> pager grep sequence
    PAGER set to 'grep sequence'
    mysql> show engine innodb statusG select sleep(60); show engine innodb statusG
    Log sequence number 84 3836410803
    1 row in set (0.06 sec)
    1 row in set (1 min 0.00 sec)
    Log sequence number 84 3838334638
    1 row in set (0.05 sec)

    mysql> pager
    Default pager wasn't set, using stdout.

    mysql>select(3838334638-3836410803)/1024/1024asMB_per_min;
    +------------+
    |MB_per_min|
    +------------+
    |1.83471203|
    +------------+
    然后拿这个值MB_per_min×60/2,就是innodb_log_file_size合理值。

         如果修改了innodb_log_file_size,关闭数据库后,要把旧的ib_logfile移走,再启动数据库,否则会崩溃.

    (2)innodb_log_buffer_size
    设置为一秒的日志大小即可

    这个参数设置 InnoDB 用来往磁盘上的日志文件写操作的缓冲区的大小。通过内存缓冲来延缓磁盘 I/O 以提高访问的效率。 因为 MySQL 每秒都会将日志缓冲区的内容刷新到日志文件,因此无需设置超过 1 秒所需的内存空间。通常设置为 8 ~ 16MB 就足够了,默认值是 1MB 

    (3) innodb_flush_log_at_trx_commit
    将 innodb_flush_log_at_trx_commit 配置设定为0;按过往经验设定为0,插入速度会有很大提高。默认为1 

    0: Write the log buffer to the log file(刷到内存的log_file中)and flush the log file (刷到硬盘)every second, but do nothing at transaction commit. 
    1:the log buffer is written out to the log file at each transaction commit and the flush to disk operation is performed on the log file 
    2:the log buffer is written out to the file at each commit, but the flush to disk operation is not performed on it (仍然每秒刷硬盘一次)








    二 理论知识

     1  数据库性能综述
    数据库系统中,写日志和写数据文件是数据库中IO消耗最大的两种操作,在这两种操作中写数据文件属于分散写,写日志文件是顺序写,因此为了保证数据库的性能,通常数据库都是保证在提交(commit)完成之前要先保证日志都被写入到日志文件中,而脏数据块则保存在数据缓存(buffer cache)中再不定期的分批写入到数据文件中。也就是说日志写入和提交操作是同步的,而数据写入和提交操作是不同步的。
    2   checkpoint--内存数据写硬盘
    checkpoint是的一个内部事件,这个事件激活以后会触发数据库写进程(DBWR)将数据缓冲(DATABUFFER CACHE)中的脏数据块写出到数据文件中。
    数据库系统中,写日志和写数据文件是数据库中IO消耗最大的两种操作,在这两种操作中写数据文件属于分散写,写日志文件是顺序写,因此为了保证数据库的性能,通常数据库都是保证在提交(commit)完成之前要先保证日志都被写入到日志文件中,而脏数据块则保存在数据缓存(buffer cache)中再不定期的分批写入到数据文件中。也就是说日志写入和提交操作是同步的,而数据写入和提交操作是不同步的。这样就存在一个问题,当一个数据库崩溃的时候并不能保证缓存里面的脏数据全部写入到数据文件中,这样在实例启动的时候就要使用日志文件进行恢复操作,将数据库恢复到崩溃之前的状态,保证数据的一致性。检查点是这个过程中的重要机制,通过它来确定,恢复时哪些重做日志应该被扫描并应用于恢复。
    一般所说的checkpoint是一个数据库事件(event),checkpoint事件由checkpoint进程(LGWR/CKPT进程)发出,当checkpoint事件发生时DBWn会将脏块写入到磁盘中,同时数据文件和控制文件的文件头也会被更新以记录checkpoint信息。

    checkpoint的作用

    checkpoint主要2个作用:
    保证数据库的一致性,这是指将脏数据写入到硬盘,保证内存和硬盘上的数据是一样的;
    缩短实例恢复的时间,实例恢复要把实例异常关闭前没有写出到硬盘的脏数据通过日志进行恢复。如果脏块过多,实例恢复的时间也会很长,检查点的发生可以减少脏块的数量,从而提高实例恢复的时间。
    通俗的说checkpoint就像word的自动保存一样。

    什么时候发生normal checkpoint

    下面这些操作将会触发checkpoint事件:
    日志切换,通过ALTER SYSTEM SWITCH LOGFILE。
    DBA发出checkpoint命令,通过ALTER SYSTEM checkpoint。
    对数据文件进行热备时,针对该数据文件的checkpoint也会进行,ALTER TABLESPACE TS_NAME BEGIN BACKUP/END BACKUP。
    当运行ALTER TABLESPACE/DATAFILE READ ONLY的时候。
    SHUTDOWN命令发出时。

    3 事物隔离级别
    ACID
    atomicity [,ætə'misəti] 原子性 
    consistency [kən'sistənsi]  一致性 
    isolation ['aisə'leiʃən] 隔离性 
    durability [,djuərə'biləti] 持久性

    InnoDB
    QPS Question Per Second
    TPS Transaction Per Second=(com_commit+com_rollback)/time

    隔离级别

    更新丢失

    脏读取

    重复读取

     

    幻读

    未授权读取READ-UNCOMMITTED

    N

    Y

    Y

     

    Y

    授权读取READ-COMMITTED

    N

    N

    Y

     

    Y

    可重复读取REPEATABLE-READ

    N

    N

    N

     

    Y

    串行SERIALIZABLE

    N

    N

    N

     

    N


    数据库并发操作存在的异常情况:
    1.更新丢失(LostUpdate):
    A和B事务并发执行,A事务执行更新后,提交;B事务在A事务更新后,B事务结束前也做了对该行数据的更新操作,然后回滚,则两次更新操作都丢失了。

    第一类丢失更新(回滚丢失,Lost update)。
    在事务A期间,事务B对数据进行了更新;在事务A撤销之后,覆盖了事务B已经提交的数据。
    SQL92没有定义这种现象,标准定义的所有隔离界别都不允许第一类丢失更新发生。

    第二类丢失更新(覆盖丢失/两次更新问题,Second lost update)。
    在事务A期间,事务B对数据进行了更新;在事务A提交之后,覆盖了事务B已经提交的数据。
    第二类丢失更新,实际上和不可重复读是同一种问题。

    2.脏读取(DirtyReads):
    A和B事务并发执行,B事务执行更新后,A事务查询B事务没有提交的数据,B事务回滚,则A事务得到的数据不是数据库中的真实数据。也就是脏数据,即和数据库中不一致的数据。

    3.不可重复读取(Non-repeatableReads):
     A和B事务并发执行,A事务查询数据,然后B事务更新该数据并提交,A再次查询该数据时,发现该数据变化了。

    4.幻读(PhantomReads):也称为幻像(幻影)。
    A和B事务并发执行,A事务查询数据,B事务插入或者删除数据并提交,A事务再次查询发现,结果集中,有以前没有的数据或者以前有的数据消失了。

    为了避免上面出现几种情况在标准SQL规范中定义了4个事务隔离级别,不同隔离级别对事务处理不同。

    1. READ-UNCOMMITTED未授权读取/未提交读
    允许脏读取但不允许更新丢失。
    如果一个事务已经开始写数据,则另外一个事务不允许同时进行写操作,但允许其他事务读此行数据。通过“排他写锁”实现。

    2. READ-COMMITTED授权读取/提交读
    允许不可重复读取但不允许脏读取。
    更新语句提交以后别的事务才能读到这个改变。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。通过“瞬间共享读锁”和“排他写锁”实现,
    在此隔离级下,SELECT命令不会返回尚未提交(Committed)的数据,也不能返回脏数据。

    3. REPEATABLE-READ可重复读取
    禁止不可重复读取和脏读取。但是有时可能出现幻影数据
    在同一个事务里面先后执行同一个查询语句的时候,确保得到的结果是一样的。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。通过“共享读锁”和“排他写锁”实现,
    在此隔离级下,用SELECT命令读取的数据在整个命令执行过程中不会被更改。此选项会影响系统的效能,非必要情况最好不用此隔离级。

    4. SERIALIZABLE串行/可串行读。
    事务只能一个接着一个地执行,但不能并发执行。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作事务访问到。
    参考自:http://www.blogjava.net/feuyeux/archive/2012/04/25/376547.html

    三 网友实践


    由于项目变态需求;需要在一个比较短时间段急剧增加数据库记录(两三天内,由于0增加至4亿)。在整个过程调优过程非常艰辛
    -
    (1)提高数据库插入性能中心思想:尽量将数据一次性写入到Data File和减少数据库的checkpoint 操作。这次修改了下面四个配置项: 
    1)将 innodb_flush_log_at_trx_commit 配置设定为0;按过往经验设定为0,插入速度会有很大提高。 

    0: Write the log buffer to the log file and flush the log file every second, but do nothing at transaction commit. 
    1:the log buffer is written out to the log file at each transaction commit and the flush to disk operation is performed on the log file 
    2:the log buffer is written out to the file at each commit, but the flush to disk operation is not performed on it 

    2)将 innodb_autoextend_increment 配置由于默认8M 调整到 128M 
    此配置项作用主要是当tablespace 空间已经满了后,需要MySQL系统需要自动扩展多少空间,每次tablespace 扩展都会让各个SQL 处于等待状态。增加自动扩展Size可以减少tablespace自动扩展次数。 

    3)将 innodb_log_buffer_size 配置由于默认1M 调整到 16M 
    此配置项作用设定innodb 数据库引擎写日志缓存区;将此缓存段增大可以减少数据库写数据文件次数。 

    4)将 innodb_log_file_size 配置由于默认 8M 调整到 128M 
    此配置项作用设定innodb 数据库引擎UNDO日志的大小;从而减少数据库checkpoint操作。 
    经过以上调整,系统插入速度由于原来10分钟几万条提升至1秒1W左右;注:以上参数调整,需要根据不同机器来进行实际调整。特别是 innodb_flush_log_at_trx_commit、innodb_log_buffer_size和 innodb_log_file_size 需要谨慎调整;因为涉及MySQL本身的容灾处理。 


    (2)提升数据库读取速度,重数据库层面上读取速度提升主要由于几点:简化SQL、加索引和分区; 经过检查程序SQL已经是最简单,查询条件上已经增加索引。我们只能用武器:表分区。 


    数据库 MySQL分区前准备:在MySQL中,表空间就是存储数据和索引的数据文件。 
    将S11数据库由于同享tablespace 修改为支持多个tablespace; 

    将wb_user_info_sina 和 wb_user_info_tx 两个表修改为各自独立表空间;(Sina:1700W数据,2.6G 大数据文件,Tencent 1400W,2.3G大数据文件); 
    分区操作: 
    将现有的主键和索引先删除 
    重现建立id,uid 的联合主键 
    再以 uid 为键值进行分区。这时候到/var/data/mysql 查看数据文件,可以看到两个大表各自独立表空间已经分割成若干个较少独立分区空间。(这时候若以uid 为检索条件进行查询,并不提升速度;因为键值只是安排数据存储的分区并不会建立分区索引。我非常郁闷这点比Oracle 差得不是一点半点。) 
    再以 uid 字段上进行建立索引。再次到/var/data/mysql 文件夹查看数据文件,非常郁闷地发现各个分区Size竟然大了。MySQL还是老样子将索引与数据存储在同一个tablespace里面。若能index 与 数据分离能够更加好管理。 


    经过以上调整,暂时没能体现出系统读取速度提升;基本都是在 2~3秒完成5K数据更新。 

    MySQL数据库插入速度调整补充资料: 

    MySQL 从最开始的时候 1000条/分钟的插入速度调高至 10000条/秒。 相信大家都已经等急了相关介绍,下面我做调优时候的整个过程。提高数据库插入性能中心思想: 
    1、尽量使数据库一次性写入Data File 
    2、减少数据库的checkpoint 操作 
    3、程序上尽量缓冲数据,进行批量式插入与提交 
    4、减少系统的IO冲突 


    根据以上四点内容,作为一个业余DBA对MySQL服务进行了下面调整: 
    修改负责收录记录MySQL服务器配置,提升MySQL整体写速度;具体为下面三个数据库变量值:innodb_autoextend_increment、innodb_log_buffer_size、innodb_log_file_size;此三个变量默认值分别为 5M、8M、8M,根据服务器内存大小与具体使用情况,将此三只分别修改为:128M、16M、128M。同时,也将原来2个 Log File 变更为 8 个Log File。此次修改主要满足第一和第二点,如:增加innodb_autoextend_increment就是为了避免由于频繁自动扩展Data File而导致 MySQL 的checkpoint 操作; 
    将大表转变为独立表空并且进行分区,然后将不同分区下挂在多个不同硬盘阵列中。 


    完成了以上修改操作后;我看到下面幸福结果: 

    获取测试结果: 
    Query OK, 2500000 rows affected (4 min 4.85 sec) 
    Records: 2500000 Duplicates: 0 Warnings: 0 
    Query OK, 2500000 rows affected (4 min 58.89 sec) 
    Records: 2500000 Duplicates: 0 Warnings: 0 
    Query OK, 2500000 rows affected (5 min 25.91 sec) 
    Records: 2500000 Duplicates: 0 Warnings: 0 
    Query OK, 2500000 rows affected (5 min 22.32 sec) 




    Records: 2500000 Duplicates: 0 Warnings: 0 
    最后表的数据量: 
    +------------+ 
    | count(*) | 
    +------------+ 
    | 10000000| 
    +------------+ 
    从上面结果来看,数据量增加会对插入性能有一定影响。不过,整体速度还是非常面议。一天不到时间,就可以完成4亿数据正常处理。预计数据库瓶颈已经被巧妙解决,结果变成程序“猿”苦逼地向我埋怨,大哥不用这么狠啊。

    四 查看mysql内存使用状况

    1. 直接登录机器使用top命令查看内存占用
            2. mysql中查看
     (1) show variables; 一般可以查看Innodb_buffer_pool_pages_data这个状态值  这只是最大的一块内存  还有些其他内存没包括在这,这个内存表示内存中缓存了多少数据页
    (2)show engine innodb status 可以看到下面这段内存使用清楚
    Dictionary memory allocated 509232
    Buffer pool size   131072
    Free buffers       0
    Database pages     131062
    Old database pages 48360 
     




    参数 innodb_buffer_pool_instances设置




    摘要:1 innodb_buffer_pool_instances可以开启多个内存缓冲池,把需要缓冲的数据hash到不同的缓冲池中,这样可以并行的内存读写。

    innodb_buffer_pool_instances 参数显著的影响测试结果,特别是非常高的 I/O 负载时。

    3 实验环境下, innodb_buffer_pool_instances=8 在很小的 buffer_pool 大小时有很大的不同,而使用大的 buffer_pool 时,innodb_buffer_pool_instances=1 的表现最棒。


    1 定义

    The number of regions that the InnoDB buffer pool is divided into. For systems with buffer pools in the multi-gigabyte range, dividing the buffer pool into separate instances can improve concurrency, by reducing contention as different threads read and write to cached pages. Each page that is stored in or read from the buffer pool is assigned to one of the buffer pool instances randomly, using a hashing function. Each buffer pool manages its own free lists, flush lists, LRUs, and all other data structures connected to a buffer pool, and is protected by its own buffer pool mutex.

    This option takes effect only when you set the innodb_buffer_pool_size to a size of 1 gigabyte or more. The total size you specify is divided among all the buffer pools. For best efficiency, specify a combination ofinnodb_buffer_pool_instances and innodb_buffer_pool_size so that each buffer pool instance is at least 1 gigabyte.

    • 测试日期: Oct-2012
    • 测试目的: 测试 MySQL 5.6.7 的表现
    • 硬件换
      • 服务器: Dell PowerEdge R710
      • CPU: 2x Intel(R) Xeon(R) CPU E5-2660 0 @ 2.20GHz
      • 内存: 192GB(这个内存太猛了)
      • 存储: Very Fast PCIe Flash Card
      • 文件系统: ext4
    • 软件
      • 操作系统: CentOS 6.3
      • MySQL 版本: 5.6.7-RC
    • 测试规范
      • 测试工具: tpcc-mysql
      • 测试数据: 2500W (~250GB of data)
      • 测试时间: 总共测试 4000 秒,但只取最后的 2000 秒,避免因为冷启动的问题导致测试结果不准确
    • 不同的测试参数: 使用几组不同的 innodb_buffer_pool_size:13, 25, 50, 75, 100, 125GB ,innodb_buffer_pool_instances1 and 8, and innodb_log_file_size2x4GB and 2x8GB.

    测试结果:

    第一个结果使用的事 2x4GB 的 InnoDB 日志文件:

    我们可看出当 innodb_buffer_pool_instances=8 在很小的 buffer_pool 大小时有很大的不同,而使用大的 buffer_pool 时,innodb_buffer_pool_instances=1 的表现最棒。

    测试结果在大的 buffer_pool 时是很稳定的,原因是 InnoDB 使用异步 flush 模式,在新的 InnoDB flush 机制下以前的问题已经修复。不过 Dimitry 告诉我需要一个更大的 InnoDB 日志文件来获得更稳定的结果。

    下面是 2x4GB vs 2x8GB innodb 日志文件大小的比较:

    很显然,使用更大的日志文件,测试结果更稳定!

    结论:

    innodb_buffer_pool_instances 参数显著的影响测试结果,特别是非常高的 I/O 负载时。

    在 MySQL 5.6 ,最终是可以获得非常稳定的吞吐,但自适应的 flush 机制仍需较大的日志文件。

    MySQL 配置如下: 
    01 [mysqld]
    02 gdb
    03  
    04 innodb_file_per_table = true
    05 innodb_data_file_path = ibdata1:100M:autoextend
    06 innodb_flush_method = O_DIRECT
    07 innodb_log_buffer_size = 256M
    08  
    09 innodb_flush_log_at_trx_commit = 1
    10 innodb_buffer_pool_size = 125G
    11 innodb_buffer_pool_instances=8
    12  
    13 innodb_log_file_size = 4G
    14 innodb_log_files_in_group = 2
    15 #####plugin options
    16 innodb_read_io_threads = 16
    17 innodb_write_io_threads = 16
    18 innodb_io_capacity = 20000
    19 innodb_io_capacity_max = 40000
    20  
    21  
    22 #not innodb options (fixed)
    23 port = 3306
    24 back_log = 50
    25 max_connections = 2000
    26 max_prepared_stmt_count=500000
    27 max_connect_errors = 10
    28 table_open_cache = 2048
    29 max_allowed_packet = 16M
    30 binlog_cache_size = 16M
    31 max_heap_table_size = 64M
    32 sort_buffer_size = 4M
    33 join_buffer_size = 4M
    34 thread_cache_size = 1000
    35 query_cache_size = 0
    36 query_cache_type = 0
    37 ft_min_word_len = 4
    38 thread_stack = 192K
    39 tmp_table_size = 64M
    40  
    41 server-id = 10
    42 #*** MyISAM Specific options
    43 key_buffer_size = 8M
    44 read_buffer_size = 1M
    45 read_rnd_buffer_size = 4M
    46 bulk_insert_buffer_size = 8M
    47 myisam_sort_buffer_size = 8M
    48 myisam_max_sort_file_size = 10G
    49 myisam_repair_threads = 1
    50 myisam_recover
    51 user=root
    52 skip-grant-tables


    转自:http://www.phpchina.com/archives/view-41968-1.html


  • 相关阅读:
    一个链表,奇数位升序偶数位降序,让链表变成升序的
    LeetCode 046 Permutations 全排列
    LeetCode 128 Longest Consecutive Sequence 一个无序整数数组中找到最长连续序列
    LeetCode 024 Swap Nodes in Pairs 交换链表中相邻的两个节点
    模板实现一个栈(内部使用动态申请的数组作为存储结构)
    004 Median of Two Sorted Arrays 两个有序数组的中位数
    静态链接与动态链接
    sizeof和strlen的区别
    const和define的区别
    lodash
  • 原文地址:https://www.cnblogs.com/catkins/p/5270537.html
Copyright © 2011-2022 走看看