对mysql优化时一个综合性的技术,主要包括 :
a: 表的设计合理化(符合3NF(范式))
表的范式,是首先符合1NF, 才能满足2NF , 进一步满足3NF。
1NF:即表的列的具有原子性,不可再分解,即列的信息,不能分解,只有数据库是关系型数据库,就自动的满足1NF
2NF:表中的记录是唯一的,就满足2NF,通常我们设计一个主键来实现
3NF:即表中不要有冗余数据, 就是说,表的信息,如果能够被推导出来,就不应该单独的设计一个字段来存放(实际工作用,冗余是有必要的,反3NF)
b: 添加适当索引(index) [四种: 普通索引、主键索引、唯一索引unique、全文索引]
1、当一张表,把某个列设为主键的时候,则该列就是主键索引
语法:alter table 表名 add primary key (列名);
2、普通索引的创建,是先创建表,然后在创建普通索引
语法:create index 索引名 on 表 (列1,列名2);
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 ...');
全文索引使用方法:
错误用法:
explain select * from articles where body like '%database%'
正确用法:
explain select * from articles where match(title,body) against('database');
- mysql自己提供的fulltext针对英文生效->sphinx (coreseek) 技术处理中文
- 全文索引对一些常用词,不会进行索引,这些词称为:停止词
4、唯一索引
当表的某列被指定为unique约束时,这列就是一个唯一索引
创建唯一索引:
create table ddd(id int primary key auto_increment , name varchar(32) unique);
create unique index 索引名 on 表名 (列表..);
检查索引:
EXPLAIN SELECT id FROM ddd
如何查询索引?
desc 表名 【该方法的缺点是:不能够显示索引名】
show index from 表名
show keys from 表名
如何删除索引?
alter table 表名 drop index 索引名;
如果删除主键索引。alter table 表名 drop primary key
如何修改索引?删除后,重新创建
索引之所以能提高速度,是使用了二叉树算法BTREE
总结: 满足以下条件的字段,才应该创建索引.
a: 肯定在where条经常使用
b: 该字段的内容不是唯一的几个值(sex)
c: 字段内容不是频繁变化.
注意事项:
把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.
3、如果条件中有or,要求使用的所有字段,都必须建立索引, 即使其中有条件带索引也不会使用。我们建议大家尽量避免使用or关键字
比如: select * from dept where dname=’xxx’ or loc=’xx’ or deptno=45
4、如果列类型是字符串,那一定要在条件中将数据使用引号引用起来。否则不使用索引。(添加时,字符串必须''), 也就是,如果列是字符串类型,就一定要用'' 把他包括起来.
5、如果mysql估计使用全表扫描要比使用索引快,则不使用索引。
如何查看索引使用的情况:
show status like ‘Handler_read%’;
handler_read_key:这个值越高越好,越高表示使用索引查询到的次数。
handler_read_rnd_next:这个值越高,说明查询低效。
c: 分表技术(水平分割、垂直分割)
水平分割:
水平分割根据某些条件将数据放到两个或多个独立的表中。水平切割将表分为多个表。每个表包含的列数相同,但是数据行更少。
通常用来水平分割表的条件有:日期时间维度、地区维度等,当然还有更多的业务维度。
例如,可以将一个包含十亿行的表水平分区成 12 个表,每个小表表示特定年份内一个月的数据。任何需要特定月份数据的查询只需引用相应月份的表。
优点:降低在查询时需要读的数据和索引的页数,同时也降低了索引的层数,加快了查询速度。
缺点:水平分割会给应用增加复杂度,它通常在查询时需要多个表名,查询所有数据需要union操作。在许多数据库应用中,这种复杂性会超过它带来的优点。
垂直分割:
把主码(主键)和一些列放到一个表,然后把主码(主键)和另外的一些列放到另一个表中。将原始表分成多个只包含较少列的表。
如果一个表中某些列常用,而另外一些列不常用,则可以采用垂直分割。
优点:
1、垂直分割可以使得行数据变小,一个数据块(Block)就能存放更多的数据,在查询时就会减少I/O次数(每次查询时读取的Block就少)。
2、垂直分割表可以达到最大化利用Cache的目的。
缺点:
1、表垂直分割后,主码(主键)出现冗余,需要管理冗余列
2、会引起表连接JOIN操作(增加CPU开销)需要从业务上规避
d: 读写[写: update/delete/add]分离
e: 存储过程 [模块化编程,可以提高速度] 使用请看我的另一篇文章《存储过程与自定义函数》
f: 对mysql配置优化 [配置最大并发数my.ini, 调整缓存大小 ]
max_connections = 200 # 最大并发数
query_cache_size = 20000000 # 缓存大小(20MB),生成环境一般几百M,学习环境1M即可,不低于40KB
查询:show variables like '%query_cache%';
g: mysql服务器硬件升级
h: 定时的去清除不需要的数据,定时进行碎片整理(MyISAM)
如何选择mysql的存储引擎?经常使用的存储引擎 myisam / innodb/ memory
MyISAM 存储:如果表对事务要求不高,同时是以查询和添加为主的,我们考虑使用myisam存储引擎。比如 bbs 中的 发帖表,回复表。
INNODB 存储:对事务要求高,保存的数据都是重要数据,我们建议使用INNODB,比如订单表,账号表。
Memory 存储:比如我们数据变化频繁,不需要入库,同时又频繁的查询和修改,我们考虑使用memory,速度极快。
MyISAM 和 INNODB的区别:
1、事务安全
2、查询和添加速度
3、支持全文索引
4、锁机制
5、外键 MyISAM 不支持外键, INNODB支持外键 (在PHP开发中,通常不设置外键,通常是在程序中保证数据的一致)
如果你的数据库的存储引擎是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');
进行碎片整理:
optimize table test100;
sql语句的小技巧:
1、在使用group by 分组查询是,默认分组后,还会排序,可能会降低速度。在group by 后面增加 order by null 就可以防止排序
EXPLAIN SELECT * FROM shirt GROUP BY owner
EXPLAIN SELECT * FROM shirt GROUP BY OWNER ORDER BY NULL
2、有些情况下,可以使用连接来替代子查询。因为使用 join,MySQL不需要在内存中创建临时表。
# 简单处理方式
select * from dept, emp where dept.deptno=emp.deptno;
# 左外连接,更ok!
select * from dept left join emp on dept.deptno=emp.deptno;
3、定位慢查询
首先我们了解mysql数据库的一些运行状态如何查询?(比如想知道当前mysql运行的时间/ 一共执行了多少次select/update/delete/ 当前连接)
SHOW STATUS;
常用的:
show status like 'uptime';
show stauts like 'com_select';
show stauts like 'com_insert';
show status like 'com_delete';
show status like 'connections';
show [session|global] status like .... 如果你不写 [session|global] 默认是session 会话,指取出当前窗口的执行,如果你想看所有(从mysql 启动到现在,则应该 global)
如何定位慢查询?
显示慢查询次数:
show status like 'slow_queries';
默认情况下,mysql认为10秒才是一个慢查询。
show variables like 'long_query_time' ; # 可以显示当前慢查询时间
set long_query_time=1 ; # 可以修改慢查询时间
把慢查询的sql记录到我们的一个日志中:
开启慢查询日志:
低版本Mysql5.0配置:找到my.ini,在[mysqld]下
log-slow-queries=d:/slowquery.log # 开启慢查询,设置记录路径
long_query_time=2 # 大于2秒的记录
高版本Mysql5.5配置:找到my.ini,在
log_slow_queries=ON
long_query_time=2
slow_query_log=ON
log_queries_not_using_indexes=ON
# slow_query_log_file=E:/Application/Category/Java/_ISCAS/SIE/slow-query.log
默认存放路径:
#Path to the database root
datadir="C:/Documents and Settings/All Users/Application Data/MySQL/MySQL Server 5.5/Data/"
这是对传智播客的一份资料进行的整理,感谢传智播客的无私付出。。。