一. MySQL优化要点

  MySQL优化是一门复杂的综合性技术,主要包括:

  1 表的设计合理化(符合 3NF,必要时允许数据冗余) 

  2.1 SQL语句优化(以查询为主)

  2.2 适当添加索引(主键索引,唯一索引,普通索引(包括联合索引),全文索引)

  3 分表技术(水平分割,垂直分割)

  4 读写分离(写包括update/delete/insert)

  5 存储过程(模块化编程,提高执行速度)

  6 MySQL配置优化

  7 数据库服务器硬件升级

  8 定时数据清理,碎片整理(MyISAM)

二. 3NF是什么

  1. 第一范式

  第一范式是最基本的范式。要求数据库表中的所有字段值都是不可分解的原子值,即要求列的原子性。

  2. 第二范式

  第二范式是建立在第一范式的基础之上的,要求数据库表中的记录(行)必须是唯一的,即要求行的唯一性。

  通常通过设计一个主键来实现(建议主键不要有具体的业务含义)。

  3. 第三范式

  满足第三范式必须要满足第二范式。要求非主键列必须直接依赖于主键,不能存在传递依赖,及表中不能有冗余数据。

  表中某字段的信息可以通过其他列推导出来,就不应该设计此列。

  反3NF:没有冗余的数据库表设计未必是最优设计,有时为了提高效率,需要降低范式标准,适当增加冗余字段。

三. SQL语句优化

  1.定位慢查询(查找执行速度慢的SQL语句)

  ① 了解MySQL数据库运行状态

  > show status like 'uptime'  #查询数据库运行时间(单位:s)

  > show [session | global] status like '[com_select | com_insert | com_update | com_delete]' #查询SQL语句执行次数

    session | global :默认为 session ,表示当前 session 的语句执行次数;global 表示数据库运行以来所有次数。

  > show status like 'connections'  #查询当前

  > show status like 'slow_queries'  #显示慢查询次数

  ② 如何定位慢查询

  a.首先构造一张大表的数据,SQL语句如下:

CREATE DATABASE temp0919;
USE temp0919; #创建表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 ; #创建表EMP雇员
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 $$
#删除自定的函数
drop function rand_string $$ #创建一个函数(随机产生字符串)
#rand_string(n INT) rand_string 是函数名 (n INT) //该函数接收一个整数
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 $$ #函数: 随机产生部门编号
drop function rand_num $$ create function rand_num( )
returns int(5)
begin
declare i int default 0;
set i = floor(10+rand()*500);
return i;
end $$ #******************************************
#向emp表中插入记录(海量的数据)
drop procedure insert_emp $$ #随即添加雇员[光标] 400w
create procedure insert_emp(in start int(10),in max_num int(10))
begin
declare i int default 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 $$ delimiter ;
#调用刚刚写好的函数, 4000000条记录,从100001号开始
call insert_emp(100001,4000000); #**************************************************************
# 向dept表中插入记录 delimiter $$
drop procedure insert_dept $$ create procedure insert_dept(in start int(10),in max_num int(10))
begin
declare i int default 0;
set autocommit = 0;
repeat
set i = i + 1;
insert into dept values ((start+i) ,rand_string(10),rand_string(8));
until i = max_num
end repeat;
commit;
end $$ delimiter ;
call insert_dept(100,10);

  

  b. MySQL默认执行时间大于10s的语句为慢查询,此处修改为1s

  > show variables like 'long_query_time'  #显示慢查询时间标准

  > set long_query_time = 1  #修改慢查询时间,当前session有效

  c. 记录慢查询到日志文件中

  默认情况下MySQL不会记录慢查询日志,需要在启动MySQL服务时,指定相应的参数,才可以记录慢查询日志。

  两种启动方式如下:

  (1) 修改配置后启动(linux : my.conf,  windows : my.ini) 

[mysqld]
#慢查询日志文件位置, 此目录文件一定要有写权限
log-slow-queries="/usr/local/mysql5.6/data/black-slow.log"
#慢查询时间标准
long_query_time = 2
#没有使用到索引的查询也将被记录在日志中
log-queries-not-using-indexes

    修改配置文件后重新启动MySQL服务:

    $ sudo $MYSQL_HOME/support-files/mysql.server start  # Linux/OSX

    > mysqld.exe   # Windows

  (2) MySQL客户端修改参数

    使用MySQL客户端登陆MySQL数据库

  > show variables like '%slow_query%'   #查看慢查询相关参数

   > show variables like 'long_query_time'    #查询慢查询时间标准

   > set global slow_query_log = ON;  #开启慢查询日志

   > set global long_query_time = 1;  #调整慢查询时间标准

  此时不需要重启MySQL服务,即可开启慢查询日志。

  

  2. 索引的维护

    索引维护相关讨论见下方第四节。

  3. 索引的使用

    ① 对于创建了联合索引的情况,只有当查询条件中使用了联合索引中最左边的列,索引才会被使用。  

ALTER TABLE dept ADD INDEX union_idx (dname, loc);

#如下则不会使用到此索引
SELECT * FROM dept WHERE loc='Beijing';

    ② 对于使用 like 的查询,左模糊查询不会使用到相应列上的索引,及 like 查询条件的左侧不能为 '%aa' 或 '_aa' 的形式。

      如果一定要针对左模糊查询条件使用索引,可以考虑使用全文索引。

    ③ 如果查询条件中带有 or ,则要求 or 中涉及到所有列都有索引,否则不会使用索引。

      建议:尽量避免使用 or 关键字。

    ④ 如果创建索引的列的类型是字符串,则查询条件中必须使用字符串,才会使用索引。    

ALTER TABLE dept ADD INDEX idx_name (dname);
# 可以使用索引
SELECT * FROM dept WHERE dname = 'Tom';
# 不会使用索引
SELECT * FROM dept WHERE dname = 235;

    ⑤ 如果MySQL判断使用全表扫描比使用索引快,则不会使用索引。(出现的情况少)

  4. explain指令的用法

  explain 指令可以查看SQL语句的执行计划,效果如下:

  

  说明:

    id :查询序列号

    select_type : 查询类型

    table:查询的表名

    type:扫描方式,all 代表全表扫描

    possible_keys:可能使用到得索引

    key:实际使用的索引

    rows:SQL语句扫描的行数

    Extra:额外信息,如排序方式等

  5 查看索引使用情况

  > show status like 'Handler_read%';

  

  handler_read_key:越高越好,表示使用索引查询的次数

  handler_read_rnd_next:越低越好,此值高说明查询低效

  6 SQL 优化小技巧

  ① 在查询语句中使用 group by 分组时,MySQL会默认对分组结果进行排序,可能会降低速度。使用 order by null 可以关闭排序。

  

  ② 有些情况下,使用连接代替子查询。使用 join 不需要在内存中创建临时表。

四. 索引

  对于SQL优化来说,最重要的方式之一是添加索引。索引分为四种:主键索引,唯一索引,普通索引,全文索引。

  1. 创建索引

  ① 主键索引:当创建一张表时,指定某列位主键,即在该列上创建了一个主键索引。   

CREATE TABLE aaa(
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL DEFAULT ''
); CREATE TABLE bbb(
id INT UNSIGNED,
name VARCHAR(50) NOT NULL DEFAULT ''
);
ALTER TABLE bob ADD PRIMARY KEY(id);

  ② 普通索引:先创建表,然后再创建普通索引,普通索引可以单独一列或多列上创建,在多列上创建的叫做联合索引

CREATE TABLE ddd(
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
card_no VARCHAR(20) NOT NULL
);
#普通索引
CREATE INDEX idx_name ON ddd(name);
#联合索引
CREATE INDEX idx_name_cardno ON ddd(name, card_no);

  ③ 唯一索引:当表的某列被指定为 UNIQUE 约束时,则在此列上创建了一个唯一索引。

CREATE TABLE ccc(
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(32) UNIQUE
) #unique字段可以为NULL,并且可以有多个NULL
CREATE TABLE ddd(
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(32) UNIQUE
); CREATE UNIQUE INDEX name_uni ON ccc(name); #在普通索引创建时加上unique关键字即为唯一索引,唯一联合索引

  ④ 全文索引:主要针对文件文本的检索,例如文章内容。全文索引只对MyISAM引擎起效。

CREATE TABLE article(
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
title VARCHAR(200) NOT NULL,
body TEXT,
FULLTEXT (title, body) # 全文索引
) ENGINE=MyISAM CHARSET UTF8; #全文索引的使用
SELECT * from article WHERE body LIKE '%mysql%'; #错误用法,不会使用全文索引 SELECT * FROM article WHERE MATCH(title, body) AGAINST ('mysql') # 正确用法 #是否使用索引可以通过explain命令查看

  注: a. 全文索引只对MyISAM引擎生效

     b. MySQL本身提供的全文索引只对英文生效

     c. 停止词:在文本中针对所有单词或字符创建索引是一个无穷大的数量级,因此对一些常用词和字符不会创建全文索引,这些词和字符被称作停止词

  2. 查询,删除,修改索引

#查询
desc table_name; #缺点:无法显示索引名称
show index(es) from table_name;
show keys from table_name; #删除
alter table table_name drop index index_name; #主键索引的删除(必须是非auto_increment)
alter table table_name drop primary key; #修改:先删除,再添加
alter table table_name drop index index_name;
alter table table_name add index index_name table_name(col_name);

  3. 索引的代价

    a. 占用更多的磁盘空间(典型的以空间换时间)

    b. 使得DML语句变慢

  4. 创建索引的依据

    a. 创建索引的列经常在WHERE条件中使用

    b. 创建索引的表达到一定数据量,数据条数过少没必要创建索引

    c. 创建索引的列的字段值不是有限的几个值,例如性别,是否上线等

    d. 创建索引的列的字段值不是频繁变化,例如记录登录次数,在线人数等字段

 

五. 分表技术

  当业务数据越来越多的时候,会导致某些数据表的数据量非常巨大,导致系统的性能下降。可以通过分表的方式改善性能。

  1. 水平分表

    将一张大表中的数据,或者即将产生大量数据的表,按照业务无关的属性随机均匀的存入多张结构相同的分表中。

    假设订单信息表,可以创建order_info_00,order_info_01...order_info_99,一共100张分表,订单编号是唯一的,每次存入的时候,用订单编号取hashcode后,再对100(分表数量)取模,得到的结果即为将要存储数据的分表的序号。

    Java中可如下操作: 

#取哈希值时有可能结果为Integer.MIN_VALUE,导致取序号出错
int index = Math.abs(orderNo.hashcode() % 100);  
String idxStr = String.format("%2d", index);
String tableName = "order_info_" + idxStr;

  2. 垂直分表

  在某些表中,可能会有占用空间比较大得字段,类型如text,varchar(3000),用于存储文章内容,回帖内容等,这些字段会严重影响系统的检索速度,此类字段查询的次数也相对较少,这个时候可以将其提取出来,单独建表存储,与原来的表共用主键id。这样在保证了数据的关联一致的同时,加快了原来表的检索速度。

  3. 数据库中文本视频类数据的存储

   通常不直接将文本或视频内容存储在数据库中,而只是存储文本或视频所在的路径,查询时按照路径去检索文件的真正内容。

  

六. 读写分离

  当系统的并发访问量特别大的时候,单一的MySQL服务器的负载特别大,导致数据库性能下降,升值造成服务器崩溃。这个时候可以考虑搭建MySQL集群,使用读写分离技术来改善这种状况。集群中包含一台master服务器,多台slave服务器,master服务器负责执行DML(insert/delete/update)语句,slave服务器负载执行select语句,主服务器通过日志文件将操作同步到从服务器上。

   。。。。

七. MySQL配置优化

  。。。。

八. 定时维护

 1.存储引擎的选择

  MyISAM引擎:对事物要求不高,数据以添加和查询为主

  InnoDB引擎:严格要求失误,保存的数据都是重要数据

MyISAM 和 InnoDB 区别
  事务支持 查询添加 全文索引 锁机制 外键支持
MyISAM 支持 表级
InnoDB 不支持 行级

  Memory 引擎:数据频繁变化,不需要入库,并且频繁查询修改,速度极快(MySQL服务重启后数据消失),可以用作缓存。

  2. MyISAM 引擎定期进行碎片整理

    使用 MyISAM 引擎的表中得数据被删除后,表数据存储所在的文件大小并不会改变,即表文件占用的空间不会释放,长此以往会严重拖慢表的查询速度。所以需要定期对使用 MyISAM 引擎的表进行碎片整理。

> OPTIMIZE TABLE table_name;

  3. 定时备份

  ① 手动备份数据库

#备份数据库,命令行下操作
$ ./mysqldump -u root -pxxxx temp dept > ~/backend/mysql-temp-dept.bak
#xxxx为 MySQL 登录密码,temp 为需要备份的数据库,dept 为需要备份的表名
#表名可以有多个,[tb1, tb2, tb3,....] #使用备份内容恢复数据,MySQL 客户端下操作
> source ~/backend/mysql-temp-dept.bak

  ②使用定时器完成自动备份

  a. Windows下

    1> 将备份指令写入一个bat脚本(mybaktask.bat): 

#mysqldump.exe路径包含空格,需要用""包围
"C:\programe files\mysql5.6.26\bin\mysqldump.exe" -u root -pxxxx temp dept >d:\temp.dept.bak

    2> 把 mybaktask.bat 做成一个计划任务

     "计算机"-(右键)"属性"-"管理"-"系统工具"-"任务计划程序"-"创建任务"

    注:windows下希望每次备份的文件名称加上时间戳,不覆盖上一次备份的文件,可以写一个PHP脚本去执行备份命令,然后再定义一个定时任务去调用PHP脚本。  

  b. Linux / OSX 下

    1> 将备份指令写入 shell 脚本(mysql-bak-task.sh)    

#!/bin/bash
/usr/local/mysql/bin/mysqldump -u root -pxxxx temp dept > /home/byron/backend/mysql-temp-`date +%s`.bak

    2> 使用 contrab 创建定时任务

$ sudo crontab -e  #编辑定时任务

# 添加如下内容
* 2 * * * /Users/byron/backEnd/mysql-bak-task.sh # 每天凌晨2点执行一次备份脚本

九. 增量备份

  MySQL会以二进制的形式,自动将用户对MySQL数据库的操作 ,记录到文件中。    

MySQL优化概述的更多相关文章

  1. mysql优化概述4

    一.分区 1.分区概念 将某张表数据,分别存储到不同的区域中. 每个分区,都是独立的表,都要存储该分区的数据,索引信息. 2.创建分区 创建表并指定分区的选项 create table 表名 ( 定义 ...

  2. mysql优化概述3

    1.前缀索引 建立索引关键字一种方案. 通常会使用字段的整体作为索引关键字. 有时,使用字段前部分数据,也可以去识别某些记录. 语法: index `索引名` (`字段`(N)); 使用字段前N个字符 ...

  3. mysql优化概述2

    一.索引的概念 利用关键字,就是记录的部分数据(某个字段,某些字段,某个字段的一部份),建立与记录位置的对应关系,就是索引.索引的关键字一定是排序的. 二.索引的类型 mysql支持四种索引: 1.主 ...

  4. Mysql优化-概述

    摘抄并用于自查笔记 为什么要优化 一个应用吞吐量瓶颈往往出现在数据库的处理速度上. 随着应用程序的使用,数据库数据逐渐增多,数据库处理压力逐渐增大. 关系型数据库的数据是存放在磁盘上,读写速度慢(与内 ...

  5. Mysql优化概述及其压力测试工具

    衡量指标 TPS:Transactions Per Second (每秒传输的事物处理个数) ,这是指服务器每秒处理的事物数,支持事物的存储引擎如Innodb等特有的一个性能指标; QPS:Queri ...

  6. mysql优化一 之 优化内容概述及开启慢查日志的相关配置

    1-1数据库优化的目的 首先是为了避免出现页面访问错误(基本有三种) (1)由于数据库连接timeout产生的页面5XX错误 (2)由于慢查询造成页面无法加载 (3)由于阻塞造成的数据无法提交 其次: ...

  7. 深入MySQL(四):MySQL的SQL查询语句性能优化概述

    关于SQL查询语句的优化,有一些一般的优化步骤,本节就介绍一下通用的优化步骤. 一条查询语句是如何执行的 首先,我们如果要明白一条查询语句所运行的过程,这样我们才能针对过程去进行优化. 参考我之前画的 ...

  8. 0104探究MySQL优化器对索引和JOIN顺序的选择

    转自http://www.jb51.net/article/67007.htm,感谢博主 本文通过一个案例来看看MySQL优化器如何选择索引和JOIN顺序.表结构和数据准备参考本文最后部分" ...

  9. MySQL优化技巧

    目录 MySQL的特点 数据类型优化 整型类型 小数类型 字符串类型 时间类型 主键类型的选择 特殊类型的数据 索引优化 一个使用Hash值创建索引的技巧 前缀索引 多列索引 聚簇索引 覆盖索引 重复 ...

随机推荐

  1. angular使用总结

    一.是否有必要加入模块化框架 1.Reqruiejs seajs的主要作用 (1)模块化,让代码易于维护. angular本身就是mvc,模块化很清晰,所以这点用不到requirejs (2)可以按需 ...

  2. Android Studio获取SHA1和MD5方法

    1,点击Build > Generate Signed APK. 2,打开命令进入C:\Program Files\Java\jdk1.6.0_39\bin(任何已安装的Java目录) 3,键入 ...

  3. gradle学习笔记

    一直想着花时间学习下gradle,今天有空.入门一下.参考:极客学院gradle使用指南,官方文档:gradle-2.12/docs/userguide/installation.html,以及百度阅 ...

  4. grep命令详解

      用法格式 grep [option] pattern file   实验文件 [root@zejin240 tmp]# cat testdir/tfile 1 #include <stdio ...

  5. Facebook Paper使用的第三方库

    Facebook Paper使用的第三方库 第三方库名 简介 链接 ACE code editor https://github.com/ajaxorg/ace Appirater 用户评分组件 ht ...

  6. ios 文件操作(NSFileManager)

    IOS的沙盒机制,应用只能访问自己应用目录下的文件,iOS不像android,没有SD卡概念,不能直接访问图像.视频等内容. iOS应用产生的内容,如图像.文件.缓存内容等都必须存储在自己的沙盒内. ...

  7. MyBatis Mapper.xml文件中 $和#的区别

    MyBatis Mapper.xml文件中 $和#的区别   网上有很多,总之,简略的写一下,作为备忘.例子中假设参数名为 paramName,类型为 VARCHAR . 1.优先使用#{paramN ...

  8. java web学习总结(十五) -------------------JSP基础语法

    任何语言都有自己的语法,JAVA中有,JSP虽然是在JAVA上的一种应用,但是依然有其自己扩充的语法,而且在JSP中,所有的JAVA语句都可以使用. 一.JSP模版元素 JSP页面中的HTML内容称之 ...

  9. maven引入的jar带了时间戳

    正常情况下,我们引入的第三方jar一般都是类似spider-1.0.5-SNAPSHOT.jar的名称,但是有些环境下,我们引入的三方jar会带上了时间戳,如下所示: spider-1.0.5-201 ...

  10. Java基础学习 -- 异常

    当异常发生时,原本要接着执行的代码不再执行,转而让其他部分的代码来处理.如果没有代码负责处理,控制台会报告异常. 异常出现时的执行机制: 异常机制最大的好处是:清晰地分开了 正常的业务逻辑 和 遇到情 ...