Innodb存储
表空间是逻辑存放所有数据的地方,默认情况下会共享一个表空间——ibdata1,但如果把innodb_file_per_table=ON后每张表可以单独放到一个表空间内,但还是有很多数据保存在共享的表ibdata1中,如undo信息等。
表空间由各种段(segment)组成,常见的段有数据段、索引段等。Innodb是索引组织的,数据段就是clustered index的叶结点。需要注意的是,不是每个对象都有段。
区(extend)是由64个连续的页组成,每个页(page)固定为16KB,所以每个区总共为1M。页是innodb最小的磁盘管理单位。
Innodb是按行进行存放的,每个区最少可以保存2条记录,否则就成链式结构了。每行数据除了自定义列以外,还会增加事务id和回滚指针列。如果没有定义primary key也没有not null的unique,则会增加6字节的RowId列作为主键。
图片来自:http://www.cnblogs.com/chjw8016/archive/2011/03/08/1976891.html
Innodb表的限制
一个表不能包含超过1000列。
内部最大键长度是3500字节,但MySQL自己限制这个到1024字节。
除了VARCHAR, BLOB和TEXT列,最大行长度稍微小于数据库页的一半。即,最大行长度大约8000字节。LONGBLOB和LONGTEXT列必须小于4GB, 总的行长度,页包括BLOB和TEXT列,必须小于4GB。InnoDB在行中存储VARCHAR,BLOB或TEXT列的前768字节,余下的存储的分散的页中。
虽然InnoDB内部地支持行尺寸大于65535,你不能定义一个包含VARCHAR列的,合并尺寸大于65535的行。
· mysql> CREATE TABLE t (a VARCHAR(8000), b VARCHAR(10000),
· -> c VARCHAR(10000), d VARCHAR(10000), e VARCHAR(10000),
· -> f VARCHAR(10000), g VARCHAR(10000));
· ERROR 1118 (42000): Row size too large. The maximum row size for the
· used table type, not counting BLOBs, is 65535. You have to change some
· columns to TEXT or BLOBs
在一些更老的操作系统上,数据文件必须小于2GB。
InnoDB日志文件的合并尺寸必须小于4GB。
最小的表空间尺寸是10MB。最大的表空间尺寸是4,000,000,000个数据库页(64TB)。这也是一个表的最大尺寸。
InnoDB表不支持FULLTEXT索引
Innodb索引
默认情况下Memory使用存储hash索引,但也支持b+tree索引。Hash索引只用于=或者<=>的等式比较,不能用来加速order by操作,只能通过关键字来搜索一行。innodb只支持b+树索引,进一步分为clustered index 与 secondary index。在一次查询中,只能使用一个索引。
Innodb是索引组织表,clustered index的叶结点保存着整行的数据。如果,定义了primary key,则clustered index就是primary key的索引;如果没有定义primary key mysql会选中第一个仅有not null列的unique索引作为主键,并把此索引当作clustered index使用;如果没找到这样的列,innodb会创建一个6字节的RowId作为主键。所以每张表有且只有一个clustered index。
Secondary index的叶结点不包括行的全部数据,包含键值以外还包括一个bookmark,可以告诉innodb到什么地方可以找到相对应的完整行数据,还保存了主键的健值。Secondary index包含主键,但不包含完整的行数据,所以innodb总是会先从secondary index的叶节点判断是否能得到所需的数据。如,
Create table t(a int, b varchar(20), primary key(a), key(b));
Explain select * from t;
会发现mysql选择了索引b,而不是a.
复合索引
复合索引是在多列(>=2)上建立的索引,又叫多列索引或联合索引。Innodb中的复合索引也是b+ tree结构。索引的数据包含多列(col1, col2, col3…),在索引中依次按照col1, col2, col3排序。如(1, 2), (1, 3),(2,0)…
使用复合索引要充分利用最左前缀原则,顾名思义,就是最左优先。如创建索引ind_col1_col2(col1, col2),那么在查询where col1 = xxx and col2 = xx或者where col1 = xxx都可以走ind_col1_col2索引。
在创建多列索引时,要根据业务需求,where子句中使用最频繁且过滤效果好的的一列放在最左边。
索引操作
可以通过DML语句操作innodb索引。因为innodb是索引组织的表,对索引的操作会造成锁表,先生成一张临时表,将数据从原始表中写到临时表,再将原始表删除,最后将临时表表名改为原始表表名!因增加、删除、修改字段会对主索引产生影响,所以也会锁表。对secondary index从Innodb plugin开始,支持快速索引创建的方法,在创建的过程中不需要重建表,所以速度会很快,同时引擎会在表上加S锁,在创建过程中只能进行读操作。
索引设计原则
1. 搜索的索引列,不一定是所要选择的列。也就是说,最适合索引的列是出现在where子句中的列,或者连接子句中指定的列,而不是出现在select关键字后的选择列表中的列。
2. 使用唯一索引。考虑某列的分布,索引的列的基数越大,索引的效果越好。例如,对性别M/F列做索引没多大用处。
3. 使用短索引。如果是对字符串进行索引,如果有可能应该指定前缀长度。
4. 利用最左前缀。尽量将使用频繁且过滤效果好的字段放“左边”
5. 不要过度索引。
6. Innodb默认会按照一定的顺序保存数据,如果明确定义了主键,则按照主键顺序保存。如果没有主键,但有唯一索引,就按照唯一索引的顺序保存。如果有几个列都是唯一的,都可以作为主键的时候,为了提高查询效率,应选择最常用访问的列作为主键。另外,innodb的secondary index都会保存主键的键值,所有主键要尽可能选择较短的数据类型。可以看出,应当尽量避免对主键的修改。经过dba的测试,保证主键的递增可以提高插入性能。
Mysql如何使用索引
1. 对于创建的多列索引,只要查询的条件中用到了最左边的列,索引一般就会被使用。
2. 对于使用like的查询,后面如果是常量并且只有%号不在第一个字符,索引才可能被使用。
3. 如果对大文本进行搜索,应该使用全文索引,而不是使用like ‘%...%’. 但不幸的是innodb不支持全文索引。
4. 如果列名是索引,使用 index_column is null将使用索引。Oracle是不行的。
5. 如果mysql估计使用索引比全表扫描更慢,最不会使用索引。
6. 如果使用memory/head表并且where条件中不使用”=”进行索引列,那么不会用到索引。Head表只有在”=”的时候才会使用索引。
7. 用or分割开的条件,如果or前的条件中的列有索引,而后面列中没有索引,那么涉及到的索引都不会被用到。
8. 不是多列索引的第一部分不会走索引。
9. 以%开始的like不会走索引
10. 如果列是字符串,那么一定要在where条件中把字符串常量值用引号引起来,否则不能走索引。因为,mysql默认把输入的常量值进行转换以后才进行检索。
11. 经过普通运算或函数运算后的索引字段不能使用索引
12. 不等于操作不能使用索,<>、not in等
13. Order by 优化:某些情况下,mysql可以使用一个索引满足order by,而不需要额外的排序。Where条件与order by 使用相同的索引,并且order by的顺序和索引顺序相同,并且order by的字段都是升序或者都是降序。
SELECT * FROM t1 ORDER BY key_part1,key_part2,... ;
SELECT * FROM t1 WHERE key_part1=1 ORDER BY key_part1 DESC, key_part2
DESC;
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 DESC;
但是以下情况不使用索引:
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC ;
--order by 的字段混合 ASC 和 DESC
SELECT * FROM t1 WHERE key2=constant ORDER BY key1 ;
-- 用于查询行的关键字与 ORDER BY 中所使用的不相同
SELECT * FROM t1 ORDER BY key1, key2 ;
-- 对不同的关键字使用 ORDER BY
可以使用explain查看sql的执行计划。
单库单表是最常见的数据库设计,例如,有一张用户(user)表放在数据库db中,所有的用户都可以在db库中的user表中查到。
单库多表
随着用户数量的增加,user表的数据量会越来越大,当数据量达到一定程度的时候对user表的查询会渐渐的变慢,从而影响整个DB的性能。如果使用mysql, 还有一个更严重的问题是,当需要添加一列的时候,mysql会锁表,期间所有的读写操作只能等待。
可以通过某种方式将user进行水平的切分,产生两个表结构完全一样的user_0000,user_0001等表,user_0000 + user_0001 + …的数据刚好是一份完整的数据。
多库多表
随着数据量增加也许单台DB的存储空间不够,随着查询量的增加单台数据库服务器已经没办法支撑。这个时候可以再对数据库进行水平区分。
分库分表规则
设计表的时候需要确定此表按照什么样的规则进行分库分表。例如,当有新用户时,程序得确定将此用户信息添加到哪个表中;同理,当登录的时候我们得通过用户的账号找到数据库中对应的记录,所有的这些都需要按照某一规则进行。
路由
通过分库分表规则查找到对应的表和库的过程。如分库分表的规则是user_id mod 4的方式,当用户新注册了一个账号,账号id的123,我们可以通过id mod 4的方式确定此账号应该保存到User_0003表中。当用户123登录的时候,我们通过123 mod 4后确定记录在User_0003中。
分库分表产生的问题,及注意事项
1. 分库分表维度的问题
假如用户购买了商品,需要将交易记录保存取来,如果按照用户的纬度分表,则每个用户的交易记录都保存在同一表中,所以很快很方便的查找到某用户的购买情况,但是某商品被购买的情况则很有可能分布在多张表中,查找起来比较麻烦。反之,按照商品维度分表,可以很方便的查找到此商品的购买情况,但要查找到买人的交易记录比较麻烦。
所以常见的解决方式有:
a.通过扫表的方式解决,此方法基本不可能,效率太低了。
b.记录两份数据,一份按照用户纬度分表,一份按照商品维度分表。
c.通过搜索引擎解决,但如果实时性要求很高,又得关系到实时搜索。
2. 联合查询的问题
联合查询基本不可能,因为关联的表有可能不在同一数据库中。
3. 避免跨库事务
避免在一个事务中修改db0中的表的时候同时修改db1中的表,一个是操作起来更复杂,效率也会有一定影响。
4. 尽量把同一组数据放到同一DB服务器上
例如将卖家a的商品和交易信息都放到db0中,当db1挂了的时候,卖家a相关的东西可以正常使用。也就是说避免数据库中的数据依赖另一数据库中的数据。
一主多备
在实际的应用中,绝大部分情况都是读远大于写。Mysql提供了读写分离的机制,所有的写操作都必须对应到Master,读操作可以在Master和Slave机器上进行,Slave与Master的结构完全一样,一个Master可以有多个Slave,甚至Slave下还可以挂Slave,通过此方式可以有效的提高DB集群的QPS.
所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。
此外,可以看出Master是集群的瓶颈,当写操作过多,会严重影响到Master的稳定性,如果Master挂掉,整个集群都将不能正常工作。
所以,1. 当读压力很大的时候,可以考虑添加Slave机器的分式解决,但是当Slave机器达到一定的数量就得考虑分库了。 2. 当写压力很大的时候,就必须得进行分库操作。
另外,可能会因为种种原因,集群中的数据库硬件配置等会不一样,某些性能高,某些性能低,这个时候可以通过程序控制每台机器读写的比重,达到负载均衡。
备份地址:http://happyenjoylife.iteye.com/admin/blogs/1042538
1.
安装mercurial
Mercurial是一个版本管理工具。
sudo apt-get install mercurial
安装mercurial的扩展,添加fclone在支持
hg clone
http://bitbucket.org/pmezard/hgforest-crew
将以下内容添加到$HOME/.hgrc文件中,如果没有则自己创建一个:
[extensions]
forest=/home/daren/hgforest-crew/forest.py
fetch=
2.
下载jdk7源码
hg fclone http://hg.openjdk.java.net/jdk7/jdk7
3.
安装gcc、g++、make等
sudo apt-get
install build-essential
4.
安装XRender
sudo apt-get install libxrender-dev
sudo apt-get install xorg-dev
5.
安装alsa
sudo apt-get install libasound2-dev
6.
Cups
sudo apt-get install libcups2-dev
7.
安装jdk6
8.
安装ant
设置ANT_HOME
9.
安装findbugs
编译需要这玩意儿有点奇怪。需要设置FINDBUGS_HOME
10.
测试编译
export LANG=C ALT_BOOTDIR=/opt/jdk1.6.0_22/
#删除JAVA_HOME
export -n JAVA_HOME
export ALT_JDK_IMPORT_PATH=/opt/jdk1.6.0_22/
make sanity BUILD_JAXWS=false BUILD_JAXP =false
在build BUILD_JAXWS和BUILD_JAXP总是提示找不到源文件,而我又暂时对只对JDK、Hotspot感兴趣,所以索性把这两个给去掉。
如果出现:Sanity check passed.则表示测试编译通过了,不过也别开心得太早,真正make的时候不保证一定没问题,也许还会缺少某些依赖。
11.
编译
export LANG=C
ALT_BOOTDIR=/opt/jdk1.6.0_22/
#删除JAVA_HOME
export -n
JAVA_HOME
export
ALT_JDK_IMPORT_PATH=/opt/jdk1.6.0_22/
#make
BUILD_JAXWS=false BUILD_JAXP=false
#make
DEBUG_NAME=fastdebug BUILD_JAXWS=false BUILD_JAXP=false
make DEBUG_NAME=all_fastdebug BUILD_JAXWS=false
BUILD_JAXP=false
如果一切正常的话在$HOME/jdk7/build/linux-i586/下就有build出来的jdk等了。