码迷,mamicode.com
首页 > 数据库 > 详细

MySQL优化

时间:2015-05-08 09:39:28      阅读:247      评论:0      收藏:0      [点我收藏+]

标签:优化   数据库   索引   

Mysql常用的存储引擎

Myasim
InnoDB
MEMORY (HEAP)

使用最广泛的还是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:









MySQL优化

标签:优化   数据库   索引   

原文地址:http://blog.csdn.net/php_1314/article/details/45566677

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!