使用最广泛的还是MyISAM与InnoDB
两种存储引擎,各有优缺点,视具体应用而定。基本的差别为:
MyISAM类型的表强调的是性能,其执行速度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持以及外键等高级数据库功能。 另外,MyISAM类型的二进制数据文件可以在不同操作系统中迁移。也就是可以直接从Windows系统拷贝到linux系统中使用。
InnoDB不支持FULLTEXT类型的索引。
InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要 扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count(*)语 句包含 where条件时,两种表的操作是一样的。
对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。
除了提供事务处理外,InnoDB 还支持行锁,提供一致性的不加锁读取,能增加并发读的用户数量并提高性能,不会增加锁的数量。
在设计数据库表的时候,首先考虑的是要满足功能需求,这是最根本的,其次是满足性能需求,再次则是满足扩展性需求,这一点在大规模系统中是必须要考虑的。 功能性需求比较容易满足,结合自己以前遇到的一些表结构问题,来谈谈对性能和扩展性需求的一些设计方法。
合理确定字段类型和长度
字段类型尽可能反映真实的数据含义,满足功能外字段应该尽可能的短。比如能用int字段的就不要用bigint,能确定字段长度的就不要用变长字段。 对于定长的字段,长度的制定也要合理,手机号就用varchar(11)。mysql里 面char、varchar和text类型在数据长度限制上不一样,性能上也不一样,选取要谨慎。标记位字段如果有bit就用bit类型,否则就用tinyint,用 int就很浪费了,对于日期类型的存储最好用整型来存储,在页面中展示时再根据需要进行转换,这样数据库建索引,查询的效率都比较高。
选取高效的主键和索引
关于主键的选取,特别需要注意,因为对表中数据的读取都直接或间接通过 主键,推荐用自增id来做主键。
索引的大小基本上由字段来决定,所以需要建立索引的字段应该简化到最小。但是有 些字段必须建立索引却又无法简化,这时候可以考虑用hash算法或加密算法计算出长度较短的值作为索引。例如url字 段不适合做索引,但是可以用一个url_md5字段来存储url的md5值 来作为索引,有效降低键值长度
什么是索引?
索引是对数据库表中一列或多列的值进行排序的一种结构。
索引的优缺点
优点
大大加快数据的检索速度.
创建唯一性索引,保证数据库表中每一行数据的唯一性
缺点
索引需要占物理空间。
当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,需要重新建立索引
精简表设计
垂直分表
user表->用户名,密码 查询的要多 用的存储引擎最好是myisam
余额,积分…… 修改的比较多 存储引擎最好是innodb 支持事务
-->两者有些冲突 选用垂直分表
水平分表
1、按照用户名首字母(a-z)分表
2、按照用户ID分表,保证每个表均匀分配,不过需要记录用户名和ID的对应关系,用memcache、redis存储即可
索引的建立及使用
B-tree
什么是索引?
索引是对数据库表中一列或多列的值进行排序的一种结构。
索引的优缺点
优点
大大加快数据的检索速度.
创建唯一性索引,保证数据库表中每一行数据的唯一性
缺点
索引需要占物理空间。
当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,需要重新建立索引
建索引的注意点:
建对的索引,避免过度索引(具体问题具体分析)
建索引的字段一定要有区分性(比如性别字段不适合建索引)
索引的数量要控制,联合索引的第一个字段一般不要再单独的建索引。
使用短索引,varchar(255)字段可以只取前十个字符见索引,对于前十个字符区分度不大的,可以考虑将字段值进行md5处理,再建索引
索引的使用要注意:
以下操作符号可以应用索引 <,<=,=,>,>=,BETWEEN,IN,LIKE不 以%开头 以下需要注意不使用索引 <>, NOT IN, LIKE %_开头 <> 可以用 a>3 or a<1 代替,NOT IN 可 以用NOT exists代替
order by索引使用
下面的情况会使用索引
SELECT * FROM t1
ORDER BY key_part1,key_part2,... ;
SELECT * FROM t1
WHERE key_part1=constant
ORDER BY key_part2;
SELECT * FROM t1
ORDER BY key_part1 DESC, key_part2 DESC;
SELECT * FROM t1
WHERE key_part1=1
ORDER BY key_part1 DESC, key_part2 DESC;
假定表t1(c1,c2,c3,c4)有一个索引idx(c1,c2,c3):
SELECT c1, c2 FROM t1 GROUP BY c1, c2;
SELECT DISTINCT c1, c2 FROM t1;
SELECT c1, MIN(c2) FROM t1 GROUP BY c1;
SELECT c1, c2 FROM t1 WHERE c1 < const GROUP BY c1, c2;
SELECT MAX(c3), MIN(c3), c1, c2 FROM t1 WHERE c2 > const GROUP BY c1, c2;
SELECT c2 FROM t1 WHERE c1 < const GROUP BY c1, c2;
SELECT c1, c2 FROM t1 WHERE c3 = const GROUP BY c1, c2;
此类查询的EXPLAIN输出显示Extra列的Using indexforgroup-by。
主动分析SQL语句的效率
在查询语句写完之后呢,要及时主动的去分析查询语句的效率,比较常用的mysql分 析命令是explain,它可以解释一个语句执行时的一些索引使用情况,还有一些其他状态
explain显示了mysql如何使用索引来处理select语句以及连接表。可以帮助选择更好的索引和写出更优 化的查询语句。
通过explain的输出,可以及时修改那些使用索引不当的语 句,如果是本身索引没有建好,则需要修改表的索引。
Explain的使用
参考资料
http://dev.mysql.com/doc/refman/5.0/en/using-explain.html
Explain里比较关键的几个值
select_type 这个表示查询的类型,一般为SIMPLE,如果出现了union或者primary,表示可能使用了表连接、子查询。
type,连接类型,也可认为是:数据扫描方式。情况如下:const/eq_ref/ref/range/index/all等,如果是index表示进行了索引扫描,如果是all表示进行了表扫描。
possible_keys 和 key,分别表示可能使用的索引和实际使用的索引,如果key为null,则表示没有使用索引。
Rows,查询涉及到的数据行数,如果这个值虚高,表示查询会有很多无谓数据扫描。
Extra 查询额外的一些说明。一般情况下为空或者using where、using index较好,如果出现Using filesort、Using temporary,表示查询还需优化。
Show index from table也可以查看索引信息
及时修正错误的索引
在项目上线后,要及时分析新增加的SQL语句的运行情况,分析慢查询日志就是一个好的方法,对慢查询日志中的查询,逐条的进行分析,看看是否是因为没有正确的使用索引导致的,需要加索引的就趁数据量还比较小的时候加,这时候代价比较小。当数据规模达到几十G的时候,在一个数据表上建索引会是一个很漫长的过程的,并且整个过程是要锁表的,这对大多数线上服务来说是不可接受的。
数据表减肥(垃圾数据处理 )
数据表的记录大小,直接影响了该表的查询速度以及该表的索引复杂度。
分析垃圾数据
在数据表运行一段时间之后,要主动思考并分析数据表中是否会有一些没有用的一些垃圾数据,如果有一些垃圾数据,则可以根据具体的情况来对这些垃圾数据进行处理,对于那些的确没有用的数据可以定期直接从数据表中删除,对于一些目前没有用但是后续可能会用的数据定期备份到一个 备份表中,以备后续的使用。
复杂的SQL语句拆分
Mysql的查询优化器不是万能的
语句越复杂,越容易选择错误的优化方案
建议大家书写简单的SQL
语句(1)的explain显示
SELECT t1.ID, t1.LemmaId, t2.LemmaTitle, t1.AuthorName, t1.AuthorId, RemoteIp, t1.LemmaContent, t2.IsPerfect, t2.IsLocked, t2.UpdatedTime,t1.IsCreate FROM tblVersion t1, tblLemma t2 WHERE t2.VersionId = t1.ID AND t2.UpdatedTime >= ‘2007-12-15‘ ORDER BY t2.UpdatedTime
desc LIMIT 13980 , 20
+----+-------------+-------+--------+---------------+---------+---------+-------------------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------+---------+---------+-------------------+--------+-------------+
| 1 | SIMPLE | t2 | range | tblvid,tesaa | tesaa | 9 | NULL | 821088 | Using where | | 1 | SIMPLE | t1 | eq_ref | PRIMARY | PRIMARY | 8 | wiki.t2.VersionId | 1 | | +----+-------------+-------+--------+---------------+---------+---------+-------------------+--------+-------------+
语句(2)跟(3)的explain显示
mysql> explain select id from tblLemma t2 where t2.UpdatedTime >= ‘2007-12-15‘ and versionid>0 ORDER BY t2.UpdatedTime desc LIMIT 13980,20;
+----+-------------+-------+-------+---------------+-------+---------+------+--------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+-------+---------+------+--------+--------------------------+
| 1 | SIMPLE | t2 | range | tblvid,tesaa | tesaa | 18 | NULL | 821088 | Using where; Using index | +----+-------------+-------+-------+---------------+-------+---------+------+--------+--------------------------+ 1 row in set (0.00 sec)
mysql> explain SELECT t1.ID, t1.LemmaId, t2.LemmaTitle, t1.AuthorName, t1.AuthorId, RemoteIp, t1.LemmaContent, t2.IsPerfect, t2.IsLocked, t2.UpdatedTime,t1.IsCreate FROM tblVersion t1, tblLemma t2 WHERE ( t2.id=1620716 OR t2.id=1620947 OR t2.id=1620948 OR t2.id=1620714
OR t2.id=1620950 OR t2.id=1620713 OR t2.id=1620981 OR t2.id=1620712 OR t2.id=1620711 OR t2.id=1620709 OR t2.id=1620956 OR t2.id=1620707 OR t2.id=1620960 OR t2.id=1338575 OR t2.id=1620972 OR t2.id=705989 OR t2.id=90826 OR t2.id=487234 OR t2.id=1620927 OR t2.id=1620925
) AND t2.VersionId = t1.ID ORDER BY t2.UpdatedTime desc ; +----+-------------+-------+--------+----------------+---------+---------+-------------------+------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len
| ref | rows | Extra | +----+-------------+-------+--------+----------------+---------+---------+-------------------+------+-----------------------------+ | 1 | SIMPLE | t2 | range | PRIMARY,tblvid | PRIMARY | 8
| NULL | 20 | Using where; Using filesort | | 1 | SIMPLE | t1 | eq_ref | PRIMARY | PRIMARY | 8 | wiki.t2.VersionId | 1 | | +----+-------------+-------+--------+----------------+---------+---------+-------------------+------+-----------------------------+
2 rows in set (0.00 sec)
避免锁表的SQL语句
比如:
insert into table select * from table1
Select for update等等
接下来我们会在mysql事务与锁中对锁定进行更详细的介绍。
SQL优化实例1
select p.orders_products_id,p.products_quantity,p.products_id,pa.products_options_id,pa.products_options_values_id from test_orders_products p left join test_orders_products_attributes pa on p.orders_products_id=pa.orders_products_id
where p.orders_id=721334;
优化前explain
+----+-------------+-------+------+---------------------------+---------------------------+---------+-------+---------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------------------+---------------------------+---------+-------+---------+-------+
| 1 | SIMPLE | p | ref | idx_orders_id_prod_id_zen | idx_orders_id_prod_id_zen | 4 | const | 1 | |
| 1 | SIMPLE | pa | ALL | NULL | NULL | NULL | NULL | 1101608 | |
+----+-------------+-------+------+---------------------------+---------------------------+---------+-------+---------+-------+
问题所在:
在两个表做连接时,第二个表连接的字段没有索引
优化方案:
create index op_id on test_orders_products_attributes (orders_products_id);
SQL优化实例1s
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: p
type: ref
possible_keys: idx_orders_id_prod_id_zen
key: idx_orders_id_prod_id_zen
key_len: 4
ref: const
rows: 1
Extra:
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: pa
type: ref
possible_keys: op_id
key: op_id
key_len: 4
ref: test_litb_cart.p.orders_products_id
rows: 1
Extra:
SQL优化实例2
优化如下类似语句:
select distinct rp.categories_id,rp.parent_id,cd.categories_name from test_region_products AS rp,test_categories_description as cd where rp.categories_id=cd.categories_id and cd.language_id=2 and rp.parent_id=0;
优化前Explain:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: rp
type: ref
possible_keys: PRIMARY,cid,pid
key: pid
key_len: 4
ref: const
rows: 34424
Extra: Using index; Using temporary
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: cd
type: eq_ref
possible_keys: PRIMARY,lid
key: PRIMARY
key_len: 8
ref: test_litb_cart.rp.categories_id,const
rows: 1
Extra:
SQL优化实例2s
优化如下类似语句:
select distinct rp.categories_id,rp.parent_id,cd.categories_name from test_region_products AS rp,test_categories_description as cd where rp.categories_id=cd.categories_id and cd.language_id=2 and rp.parent_id=0;
优化前Explain:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: rp
type: ref
possible_keys: PRIMARY,cid,pid
key: pid
key_len: 4
ref: const
rows: 34424
Extra: Using index; Using temporary
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: cd
type: eq_ref
possible_keys: PRIMARY,lid
key: PRIMARY
key_len: 8
ref: test_litb_cart.rp.categories_id,const
rows: 1
Extra:
原文地址:http://blog.csdn.net/php_1314/article/details/45566677