2009年12月15日

Innodb 文件表空间结构

    作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#gmail.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究。

      Innodb的表空间是在配置文件中定义(说是表空间有时觉的有点羞愧,和Oracle比真的差太远了),这里简单列一下表空间里的基本概念及表的分配情况。
       表空间是在配置文件中定义的几个文件简单的耦合起来,在使用中互不可少(少一个就面临DB完蛋的危险)。对于共享表空间无法确定表所在的表空间上。
      独立表空间可以做到每个表有自已的表空间(羞一下)。
       针对共享表空间,表空间中包括:回滚段,段(segment),区域(extent),数据页(page size)在表空间的体现为:
  表空间由默认16k的数据页面(page)组成,每64个连续的页面组成一个区域(extent,Oracle里熟悉的一个东东)。对于表空间的“文件(file)”在Innodb中被称为段(segment)。 回滚段(rollback segment)是一个特殊的例子,实际上rollback segment包含了多个段。对于Innodb表的索引都被分配成两个段:一个是为了 B-tree 的无叶结点(non-leaf nodes),另一个是为了叶结点(leaf nodes)。
  这是为了达到包含数据的叶结点的更好的顺序(sequentiality for the leaf nodes)。
         当表空间中的一个段增长时,InnoDB 为它个别地分配最初的 32 个页面。之后 InnoDB 再分配段的整个区域(extents)。InnoDB 会以每次 4 个区域(extents)来增加一个大段以确保数据的良好顺序。
         表空间中的某些页面包含其它页面的位图(bitmaps),所以在 InnoDB 表空间内的一些区域(extents)不能以一个整体分配给段,而只能作为个体页面。
          当发出一个查询 SHOW TABLE STATUS FROM … LIKE … 来询问表空间的剩余空间时,InnoDB 将报告表空间中所有空闲区域(extents)中确实可用的部分。InnoDB 通常会保留一些区域用于 clean-up 和其它的内部目的;这些保留的区域并不包含在剩余可用空间中。

         当从一个表中删除数据时,InnoDB 将收缩 B-tree 中相应的索引。这是依赖于释放个别的页面或区域(extents)以让其他用户使用剩余空间的删除模式。 移除(drop)一个表或删除所有记录可以保证释放空间给其他用户,但是删除记录行只有在事务回滚或 consistent read 后并不需要时才会被物理的移除

        对于独立表空间也是存一样的概念和行为,唯一区别就是每个表的数据存到指定的表空间中,rollback segment不和数据的segment在一个竞争。使用独立表空间的一个好处就是可以使数据分布相对于磁盘上更连续一点。

2009年12月13日

更改Innodb 数据页大小优化MySQL

     作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#gmail.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究。
         我们知道Innodb的数据页是16K,而且是一个硬性的规定,系统里没更改的办法,希望将来MySQL也能也Oracle一样支持多种数据页的大小。
但实际应用中有时16K显的有点大了,特别是很多业务在Oracle或是SQL SERVER运行的挺好的情况下迁到了MySQL上发现IO增长太明显的情况下,
就会想到更改数据页大小了。
  实际上innodb的数据页大小也是可以更改的,只是需要在源码层去更改,然后重新rebuild一下MySQL.
    更改办法:
    (以MySQL-5.1.38源码为例)
    位置在storage/innobase/include/univ.i ,在univ.i中查找:UNIV_PAGE_SIZE

/*
   DATABASE VERSION CONTROL
   ========================
*/
 
/* The universal page size of the database */
#define UNIV_PAGE_SIZE          (2 * 8192) /* NOTE! Currently, this has to be a
     power of 2 */
/* The 2-logarithm of UNIV_PAGE_SIZE: */
#define UNIV_PAGE_SIZE_SHIFT 14
 
/* Maximum number of parallel threads in a parallelized operation */
#define UNIV_MAX_PARALLELISM 32

   UNIV_PAGE_SIZE就是数据页大小,默认的是16K. 后面的备注里标明,该值是可以设置必须为2的次方。对于该值可以设置成4k,8k,16k,32K,64K,在大也没意义了。
同时更改了UNIV_PAGE_SIZE后需要更改 UNIV_PAGE_SIZE_SHIFT 该值是2的多少次方为UNIV_PAGE_SIZE,所以设置数据页分别情况如下:

#define UNIV_PAGE_SIZE_SHIFT 12  if UNIV_PAGE_SIZ=4K
#define UNIV_PAGE_SIZE_SHIFT 13  if UNIV_PAGE_SIZ=8K
#define UNIV_PAGE_SIZE_SHIFT 15  if UNIV_PAGE_SIZ=32K

例子:
 更改innodb的数据页为8K,相应修改为:

/*
   DATABASE VERSION CONTROL
   ========================
*/
 
/* The universal page size of the database */
#define UNIV_PAGE_SIZE          8192   /* NOTE! Currently, this has to be a
     power of 2 */
/* The 2-logarithm of UNIV_PAGE_SIZE: */
#define UNIV_PAGE_SIZE_SHIFT 13
 
/* Maximum number of parallel threads in a parallelized operation */
#define UNIV_MAX_PARALLELISM 32

重新编译,然后测试测试,再测试。Good luck!

2009年12月12日

Innodb如何使用内存

 作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#gmail.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究。
     

来源:http://www.mysqlperformanceblog.com/2006/05/30/innodb-memory-usage/

译这个文章的目的:
  最近经常被问起Innodb是如何使用内存的。该问题早已被原MySQL公司的Vadim论证过。我这里译一下他的文章供大家参考。
开始:
  这里有许多关于Innodb如何使用内存的问题。我这里将会以innodb启动时的分配情况做一个解释。一些重要的概念:
  NBLOCKS=Innodb_buffer_pool有多个页(block)=innodb_buffer_pool_size/16384(16k)
   OS_THREADS= if ( innodb_buffer_pool_size >= 1000Mb) = 50000
   else if (innodb_buffer_pool_size >= 8Mb) = 10000
   else  = 1000 (该值只用在*nixes系统上,对于Windows有一点小的区别计算OS_THREADS)

所以Innodb 使用的内存包括:
 innodb_buffer_pool_size
    innodb_additional_mem_pool_size
    innodb_log_buffer_size
    adaptive index hash ,size (innodb buffer 索引管理区)= innodb_buffer_pool_size/64
    system dictionary hash,size(innodb内部字典区) = 6 * innodb_buffer_pool_size/512
    memory for sync_array,size(用于Innodb内部syncronzation的开销)=OS_THREAD * 512
    memory for os_event,size(用于innodb内存的syncronzation的开销)=OS_THREAD * 216
    memory for locking system(内存的锁管理系统),size = 5 * 4 *NBBLOCKS
 
 最终得到innodb内存使用的计算公式为:
     Innodb_buffer_pool_size + innodb_log_buffer_size + innodb_additional_mem_pool_size + 812/16384 * innodb_buffer_pool_size + OS_THREADS * 368
 对于812/16384 * Innodb_buffer_pool_size 可以简单的用 innodb_buffer_pool_size / 20 计算,

对于OS_THREADS * 368  
    OS_THREADS * 368 = 17.5 MB  if innodb_buffer_pool_size > 1000MB
   OS_THREADS * 368 = 3.5 MB  if innodb_buffer_pool_size > 8MB

举一个例子:
   如果你的innodb_buffer_pool_size有1500MB,innodb_additional_mem_pool_size =20 MB,innodb_log_buffer_size = 8M,
   Innodb 将会向系统申请内存为= 1500M + 20M + 8M + 1500/20 M +17.5 = 1620.5M

  根据以上的条件可以算出Innodb最根本最需要多少内存,这样对于服务器的内存使用也可以有一个规划了。

对MySQL 5.1.X使用请慎重

 作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#gmail.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究。
 
      近段一直在一个项目中恶战,所以对于Blog更新慢了一点。该项目中使用了MySQL 5.1.X,使用这个版本是在我加入这个项目前就决定的。该项目基本上可以达到每秒3W的QPS(大多是基于主建的等于逻辑读写)记录都是比较长的。
近段遇到一些问题列举:
  使用MySQL-5.1.31 进行数据迁移,从SQL SERVER到MySQL迁移,共享表空间,每表一个线程,一次从SQL SERVER读取20条记录写入MySQL,迁移完毕后一个大表巨然是只能读不能写了
关闭连接池程序,保持只有一个连接进入MySQL但对那个大表也无法进行update操作,可以进行insert操作。该表有差不多2亿的数据,当时那个无语真的没法说。最终解决方法,把该表
dump了出来,又导回去可以更新。
  最新的业务上线后开着swap,没过几天就出现swap占用明显,DB反应慢的不能忍受。最终解决方法:禁用了swap分区。
  因为truncate table不能被复制及一系列问题,最终升级到mysql-5.1.31sp1(无语一个垃圾升级版本),我的意思当时升级到MySQL-5.1.37。这样就引出了另一外问题:Sort aborted,
内存溢出。以至于出现了几次严重的内存使用完毕后MySQLD被KILL掉,MySQLD进程重启,数据文件恢复造成Down机时间过长。巨汗的一次。
  痛中思痛,最终把MySQL-5.1.41,现在看来内存正常了。使用中出现了一个更可怕的问题,对一个dump出来后,导入时对该表show create table不显示结果,按ctrl+c,MySQLD就Crash,巨汗。
  万恶的MySQL-5.1.X,准备升级到MySQL-5.1.x的同学,还是我多思考一下吧。