mysql优化方案总结

u       Mysql数据库的优化技术mysql

对mysql优化时一个综合性的技术,主要包括linux

a: 表的设计合理化(符合3NF)sql

b: 添加适当索引(index) [四种: 普通索引、主键索引、惟一索引unique、全文索引]数据库

c: 分表技术(水平分割、垂直分割)编程

d: 读写[写: update/delete/add]分离缓存

e: 存储过程 [模块化编程,能够提升速度]安全

f: 对mysql配置优化 [配置最大并发数my.ini, 调整缓存大小 ]服务器

g: mysql服务器硬件升级session

h: 定时的去清除不须要的数据,定时进行碎片整理(MyISAM)mysql优化

u       什么样的表才是符合3NF (范式)

表的范式,是首先符合1NF, 才能知足2NF , 进一步知足3NF

1NF: 即表的列的具备原子性,不可再分解,即列的信息,不能分解, 只有数据库是关系型数据库(mysql/oracle/db2/informix/sysbase/sql server),就自动的知足1NF

数据库的分类

关系型数据库: mysql/oracle/db2/informix/sysbase/sql server

非关系型数据库: (特色: 面向对象或者集合)

NoSql数据库: MongoDB(特色是面向文档)

2NF: 表中的记录是惟一的, 就知足2NF, 一般咱们设计一个主键来实现

3NF: 即表中不要有冗余数据, 就是说,表的信息,若是可以被推导出来,就不该该单独的设计一个字段来存放. 好比下面的设计就是不知足3NF:

反3NF : 可是,没有冗余的数据库未必是最好的数据库,有时为了提升运行效率,就必须下降范式标准,适当保留冗余数据。具体作法是: 在概念数据模型设计时遵照第三范式,下降范式标准的工做放到物理数据模型设计时考虑。下降范式就是增长字段,容许冗余 。

u       Sql语句自己的优化

问题是: 如何从一个大项目中,迅速的定位执行速度慢的语句. (定位慢查询)

①     首先咱们了解mysql数据库的一些运行状态如何查询(好比想知道当前mysql运行的时间/一共执行了多少次select/update/delete.. / 当前链接)

show status

经常使用的:

show status like ‘uptime’ ;

show  stauts like ‘com_select’  show stauts like ‘com_insert’ ...类推 update  delete

show [session|global] status like .... 若是你不写  [session|global] 默认是session 会话,指取出当前窗口的执行,若是你想看全部(从mysql 启动到如今,则应该 global)

show status like ‘connections’;

//显示慢查询次数

show status like ‘slow_queries’;

②     如何去定位慢查询

构建一个大表(400 万)-> 存储过程构建

默认状况下,mysql认为10秒才是一个慢查询.

l       修改mysql的慢查询.

show variables like ‘long_query_time’ ; //能够显示当前慢查询时间

set long_query_time=1 ;//能够修改慢查询时间

构建大表->大表中记录有要求, 记录是不一样才有用,不然测试效果和真实的相差大.

建立:

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 ;

CREATE TABLE emp

(empno  MEDIUMINT UNSIGNED  NOT NULL  DEFAULT 0, /*编号*/

ename VARCHAR(20) NOT NULL DEFAULT "", /*名字*/

job VARCHAR(9) NOT NULL DEFAULT "",/*工做*/

mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,/*上级编号*/

hiredate DATE NOT NULL,/*入职时间*/

sal DECIMAL(7,2)  NOT NULL,/*薪水*/

comm DECIMAL(7,2) NOT NULL,/*红利*/

deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 /*部门编号*/

)ENGINE=MyISAM DEFAULT CHARSET=utf8 ;

CREATE TABLE salgrade

(

grade MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,

losal DECIMAL(17,2)  NOT NULL,

hisal DECIMAL(17,2)  NOT NULL

)ENGINE=MyISAM DEFAULT CHARSET=utf8;

测试数据

INSERT INTO salgrade VALUES (1,700,1200);

INSERT INTO salgrade VALUES (2,1201,1400);

INSERT INTO salgrade VALUES (3,1401,2000);

INSERT INTO salgrade VALUES (4,2001,3000);

INSERT INTO salgrade VALUES (5,3001,9999);

为了存储过程可以正常执行,咱们须要把命令执行结束符修改

delimiter $$

create function rand_string(n INT)

returns varchar(255) #该函数会返回一个字符串

begin

#chars_str定义一个变量 chars_str,类型是 varchar(100),默认值'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';

declare chars_str varchar(100) default

'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';

declare return_str varchar(255) default '';

declare i int default 0;

while i < n do

set return_str =concat(return_str,substring(chars_str,floor(1+rand()*52),1));

set i = i + 1;

end while;

return return_str;

end $$

若是但愿在程序中使用,是Ok!

建立一个存储过程

create procedure insert_emp(in start int(10),in max_num int(10))

begin

declare i int default 0;

#set autocommit =0 把autocommit设置成0

set autocommit = 0;

repeat

set i = i + 1;

insert into emp values ((start+i) ,rand_string(6),'SALESMAN',0001,curdate(),2000,400,rand_num());

until i = max_num

end repeat;

commit;

end $$

#调用刚刚写好的函数, 1800000条记录,从100001号开始

call insert_emp(100001,4000000);

③     这时咱们若是出现一条语句执行时间超过1秒中,就会统计到.

④     若是把慢查询的sql记录到咱们的一个日志中

在默认状况下,咱们的mysql不会记录慢查询,须要在启动mysql时候,指定记录慢查询才能够

bin\mysqld.exe - -safe-mode  - -slow-query-log [mysql5.5 能够在my.ini指定]

bin\mysqld.exe –log-slow-queries=d:/abc.log [低版本mysql5.0能够在my.ini指定]

先关闭mysql,再启动, 若是启用了慢查询日志,默认把这个文件放在

my.ini 文件中记录的位置

#Path to the database root

datadir="C:/Documents and Settings/All Users/Application Data/MySQL/MySQL Server 5.5/Data/"

⑤     测试,能够看到在日志中就记录下咱们的mysql慢sql语句.

优化问题.

经过 explain 语句能够分析,mysql如何执行你的sql语句, 这个工具的使用放一下,一会说.

添加索引 【小建议: 】

u       四种索引(主键索引/惟一索引/全文索引/普通索引)

  1. 添加

1.1主键索引添加

当一张表,把某个列设为主键的时候,则该列就是主键索引

create table aaa

(id int unsigned primary key auto_increment ,

name varchar(32) not null defaul ‘’);

这是id 列就是主键索引.

若是你建立表时,没有指定主键索引,也能够在建立表后,在添加, 指令:

alter table 表名 add primary key (列名);

举例:

create table bbb (id int , name varchar(32) not null default ‘’);

alter table bbb add primary key (id);

1.2普通索引

通常来讲,普通索引的建立,是先建立表,而后在建立普通索引

好比:

create table ccc(

id int unsigned,

name varchar(32)

)

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

1.3建立全文索引

全文索引,主要是针对对文件,文本的检索, 好比文章, 全文索引针对MyISAM有用.

建立 :

CREATE TABLE articles (

id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,

title VARCHAR(200),

body TEXT,

FULLTEXT (title,body)

)engine=myisam charset utf8;

INSERT INTO articles (title,body) VALUES

('MySQL Tutorial','DBMS stands for DataBase ...'),

('How To Use MySQL Well','After you went through a ...'),

('Optimizing MySQL','In this tutorial we will show ...'),

('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),

('MySQL vs. YourSQL','In the following database comparison ...'),

('MySQL Security','When configured properly, MySQL ...');

如何使用全文索引:

错误用法:

select * from articles where body like ‘%mysql%’; 【不会使用到全文索引】

证实:

explain  select * from articles where body like ‘%mysql%’

正确的用法是:

select * from articles where match(title,body) against(‘database’); 【能够】

说明:

  1. 在mysql中fulltext 索引只针对 myisam生效

  2. mysql本身提供的fulltext针对英文生效->sphinx (coreseek) 技术处理中文

  3. 使用方法是 match(字段名..) against(‘关键字’)

  4. 全文索引一个 叫 中止词,  由于在一个文本中,建立索引是一个无穷大的数,所以,对一些经常使用词和字符,就不会建立,这些词,称为中止词.

1.4惟一索引

①当表的某列被指定为unique约束时,这列就是一个惟一索引

create table ddd(id int primary key auto_increment , name varchar(32) unique);

这时, name 列就是一个惟一索引.

unique字段能够为NULL,并能够有多NULL, 可是若是是具体内容,则不能重复.

主键字段,不能为NULL,也不能重复.

②在建立表后,再去建立惟一索引

create table eee(id int primary key auto_increment, name varchar(32));

create unique index 索引名  on 表名 (列表..);

  1. 查询索引

desc 表名 【该方法的缺点是: 不可以显示索引名.】

show index(es) from 表名

show keys from 表名

  1. 删除

alter table 表名 drop index 索引名;

若是删除主键索引。

alter table 表名 drop primary key       [这里有一个小问题]

  1. 修改

先删除,再从新建立.

u       索引使用的注意事项

索引的代价:

  1. 占用磁盘空间

  2. 对dml操做有影响,变慢

u       在哪些列上适合添加索引?

总结: 知足如下条件的字段,才应该建立索引.

a: 确定在where条常用 b: 该字段的内容不是惟一的几个值(sex) c: 字段内容不是频繁变化.

u       使用索引的注意事项

把dept表中,我增长几个部门:

alter table dept add index my_ind (dname,loc); //  dname 左边的列,loc就是右边的列

说明,若是咱们的表中有复合索引(索引做用在多列上), 此时咱们注意:

1,  对于建立的多列索引,只要查询条件使用了最左边的列,索引通常就会被使用。

explain select * from dept where loc='aaa'\G

就不会使用到索引

2,对于使用like的查询,查询若是是  ‘%aaa’ 不会使用到索引

‘aaa%’ 会使用到索引。

好比: explain select * from dept where dname like '%aaa'\G

不能使用索引,即,在like查询时,关键的 ‘关键字’ , 最前面,不能使用 % 或者 _这样的字符., 若是必定要前面有变化的值,则考虑使用 全文索引->sphinx.

  1. 若是条件中有or,即便其中有条件带索引也不会使用。换言之,就是要求使用的全部字段,都必须创建索引, 咱们建议你们尽可能避免使用or 关键字

select * from dept where dname=’xxx’ or loc=’xx’ or deptno=45

  1. 若是列类型是字符串,那必定要在条件中将数据使用引号引用起来。不然不使用索引。(添加时,字符串必须’’), 也就是,若是列是字符串类型,就必定要用 ‘’ 把他包括起来.

  1. 若是mysql估计使用全表扫描要比使用索引快,则不使用索引。

explain 能够帮助咱们在不真正执行某个sql语句时,就执行mysql怎样执行,这样利用咱们去分析sql指令.

u       如何查看索引使用的状况:

show status like ‘Handler_read%’;

你们能够注意:handler_read_key:这个值越高越好,越高表示使用索引查询到的次数。

handler_read_rnd_next:这个值越高,说明查询低效。

u       sql语句的小技巧

  1. 在使用group by 分组查询是,默认分组后,还会排序,可能会下降速度.

好比:

在group by 后面增长 order by null 就能够防止排序.

  1. 有些状况下,可使用链接来替代子查询。由于使用join,MySQL不须要在内存中建立临时表。

select * from dept, emp where dept.deptno=emp.deptno; [简单处理方式]

select * from dept left join emp on dept.deptno=emp.deptno;  [左外链接,更ok!]

u       如何选择mysql的存储引擎

在开发中,咱们常用的存储引擎 myisam / innodb/ memory

myisam 存储: 若是表对事务要求不高,同时是以查询和添加为主的,咱们考虑使用myisam存储引擎. ,好比 bbs 中的 发帖表,回复表.

INNODB 存储: 对事务要求高,保存的数据都是重要数据,咱们建议使用INNODB,好比订单表,帐号表.

问 MyISAM 和 INNODB的区别

1. 事务安全

2. 查询和添加速

3. 支持全文索引

4. 锁机制

5. 外键 MyISAM 不支持外键, INNODB支持外键. (在PHP开发中,一般不设置外键,一般是在程序中保证数据的一致)

Memory 存储,好比咱们数据变化频繁,不须要入库,同时又频繁的查询和修改,咱们考虑使用memory, 速度极快.

u       若是你的数据库的存储引擎是myisam,请必定记住要定时进行碎片整理

举例说明:

create table test100(id int unsigned ,name varchar(32))engine=myisam;

insert into test100 values(1,’aaaaa’);

insert into test100 values(2,’bbbb’);

insert into test100 values(3,’ccccc’);

咱们应该定义对myisam进行整理

optimize table test100;

mysql_query(“optimize tables $表名”);

相关文章
相关标签/搜索