免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3341 | 回复: 0

转摘-mysql优化技术 [复制链接]

论坛徽章:
4
CU大牛徽章
日期:2013-03-13 15:32:35CU大牛徽章
日期:2013-03-13 15:38:15CU大牛徽章
日期:2013-03-13 15:38:52戌狗
日期:2013-12-27 15:08:11
发表于 2012-03-29 11:38 |显示全部楼层
本帖最后由 小版主杀手 于 2012-03-29 11:50 编辑

转摘:传智播客 韩顺平

1.数据库优化工作
对于一个以数据为中心的应用,数据库的好坏直接影响到程序的性能,因此数据库性能至关重要。一般来说,要保证数据库的效率,要做好以下四个方面的工作:
① 数据库设计
② sql语句优化
③ 数据库参数配置
④ 恰当的硬件资源和操作系统
这个顺序也表现了这四个工作对性能影响的大小

2.数据库表设计
通俗地理解三个范式,对于数据库设计大有好处。在数据库设计中,为了更好地应用三个范式,就必须通俗地理解三个范式(通俗地理解是够用的理解,并不是最科学最准确的理解):
第一范式:1NF是对属性的原子性约束,要求属性具有原子性,不可再分解;(只要是关系型数据库都满足1NF)
第二范式:2NF是对记录的惟一性约束,要求记录有惟一标识,即实体的惟一性;
第三范式:3NF是对字段冗余性的约束,即任何字段不能由其他字段派生出来,它要求字段没有冗余。 没有冗余的数据库设计可以做到。
但是,没有冗余的数据库未必是最好的数据库,有时为了提高运行效率,就必须降低范式标准,适当保留冗余数据。具体做法是: 在概念数据模型设计时遵守第三范式,降低范式标准的工作放到物理数据模型设计时考虑。降低范式就是增加字段,允许冗余。

3.数据库设计
举例说明什么事适度冗余,或者说有理由的冗余!
图片1.png

*上面这个就是不合适的冗余,原因是:
在这里,为了提高学生活动记录的检索效率,把单位名称冗余到学生活动记录表里。单位信息有500条记录,而学生活动记录在一年内大概有200万数据量。 如果学生活动记录表不冗余这个单位名称字段,只包含三个int字段和一个timestamp字段,只占用了16字节,是一个很小的表。而冗余了一个 varchar(32)的字段后则是原来的3倍,检索起来相应也多了这么多的I/O。而且记录数相差悬殊,500 VS 2000000 ,导致更新一个单位名称还要更新4000条冗余记录。由此可见,这个冗余根本就是适得其反。

数据库设计
图片2.png
给学生说一个相册浏览次数的设计案例

4.SQL语句优化
SQL优化的一般步骤:
通过show status命令了解各种SQL的执行频率。
定位执行效率较低的SQL语句-(重点select)
通过explain分析低效率的SQL语句的执行情况
确定问题并采取相应的优化措施

--select语句分类
Select
Dml数据操作语言(insert update delete)
dtl 数据事物语言(commit rollback savepoint)
Ddl数据定义语言(create alter drop..)
Dcl(数据控制语言) grant revoke

Show status 常用命令
--查询本次回话
Show session status like ‘com_%’;     //show session status like ‘Com_select’
--查询全局
Show global status like ‘com_%’;

SQL语句优化-show参数
MySQL客户端连接成功后,通过使用show [session|global] status 命令可以提供服务器状态信息。其中的session来表示当前的连接的统计结果,global来表示自数据库上次启动至今的统计结果。默认是session级别的。 下面的例子: show status like ‘Com_%’; 其中Com_XXX表示XXX语句所执行的次数。 重点注意:Com_select,Com_insert,Com_update,Com_delete通过这几个参数,可以容易地了解到当前数据库的应用是以插入更新为主还是以查询操作为主,以及各类的SQL大致的执行比例是多少。
还有几个常用的参数便于用户了解数据库的基本情况。 Connections:试图连接MySQL服务器的次数 Uptime:服务器工作的时间(单位秒) Slow_queries:慢查询的次数 (默认是10)

show status like ‘Connections’
show status like ‘Uptime’
show status like ‘Slow_queries’
如何查询mysql的慢查询时间
Show variables like 'long_query_time';
5. 修改mysql 慢查询时间
set long_query_time=2


SQL语句优化-定位慢查询
在默认情况下mysql不记录慢查询日志,需要在启动的时候指定
        bin\mysqld.exe - -slow-query-log
通过慢查询日志定位执行效率较低的SQL语句。慢查询日志记录了所有执行时间超过long_query_time所设置的SQL语句。 show variables like ‘long_query_time’; set long_query_time=2;
测试语句
        select * from emp e,dept d where e.empno=123451  and e.deptno=d.deptno;
        查看慢查询日志:默认为数据目录data中的host-name-slow.log。低版本的mysql需要通过在开启mysql时使用- -log-slow-queries[=file_name]来配置

***如何定位慢查询
Show variables like 'long_query_time';
可以重新设置 set long_query_time=2
****测试语句***
select * from emp e,dept d where e.empno=123451  and e.deptno=d.deptno;
如果带上order by e.empno 速度就会更慢,有时会到1min多.
****在默认情况下,mysql不会记录慢查询的语句,需要启用这个选项,
该慢查询日志会放在data目录下[在mysql5.0这个版本中时放在 mysql安装目录/data/下],在 mysql5.5.19下是需要查看
my.ini 的 datadir="C:/Documents and Settings/All Users/Application Data/MySQL/MySQL Server 5.5/Data/“
来确定.

SQL语句优化-explain分析问题
Explain select * from emp where ename=“zrlcHd” 会产生如下信息: select_type:表示查询的类型。 table:输出结果集的表 type:表示表的连接类型 possible_keys:表示查询时,可能使用的索引 key:表示实际使用的索引 key_len:索引字段的长度 rows:扫描的行数 Extra:执行情况的描述和说明

建立适当的索引
说起提高数据库性能,索引是最物美价廉的东西了。不用加内存,不用改程序,不用调sql,只要执行个正确的’create index’,查询速度就可能提高百倍千倍,这可真有诱惑力。可是天下没有免费的午餐,查询速度的提高是以插入、更新、删除的速度为代价的,这些写操作,增加了大量的I/O。
这里我们举例说明索引的好处(快速体验案例)
是不是建立一个索引就能解决所有的问题?ename
上没有建立索引会怎样?
select * from emp where ename=‘axJxC’;
---测试案例命令如下 (最好以 select * from emp e,dept d where e.empno=123451 )
*添加主键
ALTER TABLE emp ADD PRIMARY KEY(empno);
*删除主键
alter table emp drop primary key

索引的原理说明
没有索引为什么会慢?
使用索引为什么会快?
索引的代价
磁盘占用
对dml(update delete insert)语句的效率影响
哪些列上适合添加索引
较频繁的作为查询条件字段应该创建索引
        select * from emp where empno = 1
唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件
        select * from emp where sex = '男'
更新非常频繁的字段不适合创建索引
        select * from emp where logincount = 1
不会出现在WHERE子句中字段不该创建索引:)

索引的类型
主索引,主键自动的为主索引 (类型Primary)
唯一索引 (UNIQUE)
普通索引 (INDEX)
全文索引 (FULLTEXT)(只有MyISAM存储引擎支持) sphinx + 中文分词    coreseek
        综合使用=>复合索引
**四种索引的类型可以通过phpmyadmin创建一个索引的时候,让学员明确的看到
**简述mysql四种索引的区别
PRIMARY 索引 =》在主键上自动创建
UNIQUE 索引=> 相当于INDEX + Unique
INDEX 索引=>就是普通索引
FULLTEXT => 只在MYISAM 存储引擎支持, 目的是全文索引,在内容系统中用的多, 在全英文网站用多(英文词独立). 中文数据不常用,意义不大 国内全文索引通常 使用 sphinx 来完成.

**复合索引
create index 索引名 on 表名(列1,列2);

索引的使用
建立索引 create [UNIQUE|FULLTEXT]  index index_name on tbl_name (col_name [(length)] [ASC | DESC] , …..); alter table table_name ADD INDEX [index_name] (index_col_name,...)
        添加主键(索引) ALTER TABLE 表名 ADD PRIMARY KEY(列名,..); 联合主键
删除索引 DROP INDEX index_name ON tbl_name; alter table table_name drop index index_name;
        删除主键(索引)比较特别: alter table t_b drop primary key;
查询索引(均可) show index from table_name; show keys from table_name; desc table_Name;

查询要使用索引最重要的条件是查询条件中需要使用索引。
下列几种情况下有可能使用到索引: 1,对于创建的多列索引,只要查询条件使用了最左边的列,索引一般就会被使用。 2,对于使用like的查询,查询如果是  ‘%aaa’ 不会使用到索引
        ‘aaa%’ 会使用到索引。
下列的表将不使用索引: 1,如果条件中有or,即使其中有条件带索引也不会使用。 2,对于多列索引,不是使用的第一部分,则不会使用索引。 3,like查询是以%开头 4,如果列类型是字符串,那一定要在条件中将数据使用引号引用起来。否则不使用索引。 5,如果mysql估计使用全表扫描要比使用索引快,则不使用索引。
测试案例(就在前面的dept表上做演示.)
CREATE TABLE dept(
deptno MEDIUMINT   UNSIGNED  NOT NULL  DEFAULT 0,
dname VARCHAR(20)  NOT NULL  DEFAULT "",
loc VARCHAR(13) NOT NULL DEFAULT ""
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
--放入数据,前面应该已经添加了,如果没有则需要重新添加
--测试开始.
添加一个主键索引
alter table dept add primary key (deptno)
--测试语句
explain select * from dept where deptno=105\G;
结果是:
mysql> explain select * from dept where deptno=105\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: dept
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 3
          ref: const
         rows: 1
        Extra:
1 row in set (0.00 sec)

--创建多列索引
alter table dept add index myind (dname,loc);
--证明对于创建的多列索引,只要查询条件使用了最左边的列,索引一般就会被使用
explain select * from dept where dname=‘rjTUPqjZvf’\G; 会显示使用到了索引myind
explain select * from dept where loc=‘MsBDpMRX’\G; 不会显示使用到了索引myind
--对于使用like的查询
explain select * from dept where dname like ‘%rjTUPqjZvf’\G; 不会显示使用到了索引myind
explain select * from dept where dname like ‘rjTUPqjZvf%’\G; 会显示使用到了索引myind
--如果条件中有or,即使其中有条件带索引也不会使用
--为了演示,我们把复合索引删除,然后只在dname上加入索引.
alter table dept drop index myind
alter table dept add index myind (dname)
explain select * from dept where dname=‘aaa’ or loc=‘aa’\G;//就不会使用到dname列上的
--如果列类型是字符串,那一定要在条件中将数据使用引号引用起来。否则不使用索引
select * from dept from dname=1234\G //不会使用到索引
select * from dept from dname=‘1234’\G //会使用到索引

查看索引的使用情况 show status like ‘Handler_read%’; 大家可以注意: handler_read_key:这个值越高越好,越高表示使用索引查询到的次数。
        handler_read_rnd_next:这个值越高,说明查询低效。
常用SQL优化
大批量插入数据 对于MyISAM: alter table table_name disable keys; loading data; alter table table_name enable keys; 对于Innodb: 1,将要导入的数据按照主键排序 2,set unique_checks=0,关闭唯一性校验。 3,set autocommit=0,关闭自动提交。

优化group by 语句 默认情况,MySQL对所有的group by col1,col2进行排序。这与在查询中指定order by col1, col2类似。如果查询中包括group by但用户想要避免排序结果的消耗,则可以使用order by null禁止排序
有些情况下,可以使用连接来替代子查询。 因为使用join,MySQL不需要在内存中创建临时表。(讲解)
如果想要在含有or的查询语句中利用索引,则or之间的每个条件列都必须用到索引,如果没有索引,则应该考虑增加索引(与环境相关 讲解)
        select * from 表名 where 条件1=‘’ or 条件2=‘tt’
explaine select * from dept group by dname; =>这时显示 extra: using filesort 说明会进行排序
explaine select * from dept group by dname order by null =>这时不含有显示 extra: using filesort 说明不会进行排序

5.选择合适的存储引擎
MyISAM:默认的MySQL存储引擎。如果应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完整性、并发性要求不是很高。其优势是访问的速度快。
InnoDB:提供了具有提交、回滚和崩溃恢复能力的事务安全。但是对比MyISAM,写的处理效率差一些并且会占用更多的磁盘空间。
MyISAM 在插入数据时,默认放在最后. ,删除数据后,空间不回收.(不支持事务和外键)
InnoDB 支持事务和外键

6.选择合适的数据类型

在精度要求高的应用中,建议使用定点数来存储数值,以保证结果的准确性。
对于存储引擎是MyISAM的数据库,如果经常做删除和修改记录的操作,要定时执行optimize table table_name;功能对表进行碎片整理。
日期类型要根据实际需要选择能够满足应用的最小存储的早期类型
create table bbs(id int ,con varchar(1024) , pub_time int);
date(‘Ymd’,时间-3*24*60*60); 2038年-1-19

对于使用浮点数和定点数的案例说明
create table temp1( t1 float(10,2), t2 decimal(10,2));
insert into temp1 values(1000000.32,1000000,32); 发现 t1 成了 1000000.31 所以有问题.
对于optimize table 表名 演示
create table temp2( id int) engine=MyISAM;
insert into temp2 values(1); insert into temp2 values(2); insert into temp2 values(3);
insert into temp2 select * from temp2;--复制
delete from temp2 where id=1; 发现 该表对于的数据文件没有变小
定期执行 optimize table temp2 发现表大小变化,碎片整理完毕


&&对于InnoDB它的数据会存在data/ibdata1目录下,在data/数据库/只有一个 *.frm表结构文件.

对表进行水平划分
如果一个表的记录数太多了,比如上千万条,而且需要经常检索,那么我们就有必要化整为零了。如果我拆成100个表,那么每个表只有10万条记录。当然这 需要数据在逻辑上可以划分。一个好的划分依据,有利于程序的简单实现,也可以充分利用水平分表的优势。比如系统界面上只提供按月查询的功能,那么把表按月 拆分成12个,每个查询只查询一个表就够了。如果非要按照地域来分,即使把表拆的再小,查询还是要联合所有表来查,还不如不拆了。所以一个好的拆分依据是 最重要的。UNION
**学生情况
**查询电话费,近三个月的数据放入一张表,一年内的放入到另一张表
图片3.png
每个学生做过的题都记录在这个表里,包括对题和错题。每个题会对应一个或多个知识点,我们需要根据错题来分析学生在哪个知识点上掌握的不足。这个表很容 易达到千万级,迫切需要拆分,那么根据什么来拆呢?从需求上看,无论是老师还是学生,最终会把焦点落在一个学生的身上。学生会关心自己,老师会关心自己班 的学生。而且每个学科的知识点是不同的。所以我们很容易想到,联合学科和知识点两个字段来拆分这个表。这样拆下来,每个表大概2万条数据,检索效率非常 高。(使用hash方法来处理)

对表进行垂直划分
有些表记录数并不多,可能也就2、3万条,但是字段却很长,表占用空间很大,检索表时需要执行大量I/O,严重降低了性能。这个时候需要把大的字段拆分到另一个表,并且该表与原表是一对一的关系。 (JOIN)

图片4.jpg
【试题内容】、【答案信息】两个表,最初是作为几个字段添加到【试题信息】里的,可以看到试题内容和答案这两个字段很长,在表里有3万记录时,表已经占 了1G的空间,在列试题列表时非常慢。经过分析,发现系统很多时候是根据【册】、【单元】、类型、类别、难易程度等查询条件,分页显示试题详细内容。而每 次检索都是这几个表做join,每次要扫描一遍1G的表。我们完全可以把内容和答案拆分成另一个表,只有显示详细内容的时候才读这个大表,由此 就产生了【试题内容】、【答案信息】两个表。

选择适当的字段类型,特别是主键
选择字段的一般原则是保小不保大,能用占用字节小的字段就不用大字段。比如主键, 建议使用自增类型,这样省空间,空间就是效率!按4个字节和按32个字节定位一条记录,谁快谁慢太明显了。涉及到 几个表做join时,效果就更明显了。
        es1234 , 建议使用一个不含业务逻辑的id做主角

        student表
     id stuno         stuname         adress
     1  es1234         顺平                    北京
示详细内容的时候才读这个大表,由此 就产生了【试题内容】、【答案信息】两个表。

文件、图片等大文件用文件系统存储
数据库只存储路径。图片和文件存放在文件系统,甚至单独放在一台服务器(图床).

数据库参数配置
最重要的参数就是内存,我们主要用的innodb引擎,所以下面两个参数调的很大
  innodb_additional_mem_pool_size = 64M
  innodb_buffer_pool_size =1G
对于myisam,需要调整key_buffer_size
        当然调整参数还是要看状态,用show status语句可以看到当前状态,以决定改调整哪些参数

合理的硬件资源和操作系统   
如果你的机器内存超过4G,那么毋庸置疑应当采用64位操作系统和64位mysql

读写分离
        如果数据库压力很大,一台机器支撑不了,那么可以用mysql复制实现多台机器同步,将数据库的压力分散。
建议使用 linux下安装源码包

Master
  Slave1
  Slave2
  Slave3
        主库master用来写入,slave1—slave3都用来做select,每个数据库
分担的压力小了很多。
  要实现这种方式,需要程序特别设计,写都操作master,读都操作
slave,给程序开发带来了额外负担。当然目前已经有中间件来实现这个
代理,对程 序来读写哪些数据库是透明的。官方有个mysql-proxy,但是
还是alpha版本的。新浪有个amobe for mysql,也可达到这个目的,结构
如下 
图片5.png


转摘:传智播客 韩顺平
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP