MySQL数据库优化

MySQL数据库优化

主流版本:

mysql 5.6 		5.6.36	5.38	5.6.40

mysql5.7		5.7.18	5.7.20	5.7.22

企业版本选择:6-12月之间的GA

mysql c/s结构

两种连接方式:
tcp/ip(远程,本地):
mysql -uroot -p123 -h 10.0.0.200 -P3306
socket(本地):
mysql -uroot -p123 /tmp/mysql.sock

mysql实例

实例=mysqld+内存结构
	mysqld -------->master thread ------->N thread -------->内存结构
	

mysql三层结构

连接层
1.提供连接协议
2.用户验证
3.提供专用链接线程
SQL层
1.接收上层的命令
2.语法检测
3.语义(sql类型),权限
	SQL类型:DDL定义语言 dcl数据控制语言  dml数据操作语言  dql数据查询
4.专用解析器解析SQL,解析成执行计划
5.优化器,帮我们选择一个代价最低的执行计划
6.按照优化器的选择,执行SQL语句,得出获取数据方法
7.查询缓存:默认是关闭的 一般会使用redis产品替代
8.记录日志:查询日志,二进制日志
存储引擎层
按照SQL层结构,找相应数据,结构化成表的形式

MySQL的逻辑结构

库:存储表的地方
表:二维表
	表名字
	表的属性
	列:列名字,列属性(数据类型,约束,其他定义)
	记录:数据行

SQL语句(sql92)

SQL种类

ddl数据定义语句
dcl数据控制语句
dml数据操作语句
dql数据查询语句

不同分类语句作用

ddl

	库
	create database
	drop database
	alter database
	SQL语句规范:
		1.关键字大写,字面量小写
		2.库名字只能是小写,不能有数字开头,不能是预留的关键字
		3.库名和业务名字有关
		4.必须加字符集
	
	
	
	表
	CREATE TABLE
	DROP  TABLE
	ALTER TABLE
	
	
	CREATE TABLE t1(id INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID)ENDINE INNODB CHARSET utf8mb4;
	
	规范:
		1.关键字大写,字面量小写
		2.表名字只能是小写,不能有数字开头,不能是预留的关键字
		3.表名字和业务有关
		4.必须加存储引擎和字符集
		5.使用合适的数据类型
		6.必须要有主键
		7.必须加注释
		8.避免外键
		9.建立合理的索引
	
	

DCL(数据控制语句):

grant
revoke
lock

DML(数据操作语句):

insert
update
delete

规范:
	1.insert语句按批量插入数据
	2.update必须加where条件
	3.delete尽量替换为update
	4.清空全表数据,truncate

DQL:

select

show

规范:
	1.select尽量避免使用select * from t;
	2.select语句尽量加等值的where条件
	3.select 语句对于范围查询
	4.select 的where条件查询结果集尽量减少
	5.不要出现3表以上的表连接,避免子查询
	6.where条件中不要出现函数操作

mysql初始化数据

/usr/local/mysql/bin/mysqld --initialize-insecure  --user=mysql --datadir=/opt/mysql/data --basedir=/opt/mysql

Linux中mysql的配置

vim /etc/my.cnf
[mysqld]
basedir = /user/local/mysql
datadir = /user/local/mysql/mydata
socket  = /tmp/mysql.sock
log_error = /var/log/mysql.log
user = mysql
port = 3306
server_id = 6
[mysql]
socket = /tmp/mysql.sock

作用:

1.影响服务端的启动

标签 [mysqld]

​ [mysqld_safe]

​ [server]

mysql多实例

创建相关目录

mkdir -p /data/330{7..9}/data 

创建配置文件

cat>> /data/3307/my.cnf<<EOF
[mysqld]
basedir=/opt/mysql              
datadir=/data/3307/data
user=mysql
socket=/data/3307/mysql.sock
port=3307 
server_id=3307
EOF

#复制到其它目录
cp /data/3307/my.cnf /data/3308 
cp /data/3307/my.cnf /data/3309 

#修改其它目录的文件
sed -i 's#3307#3308#g' /data/3308/my.cnf 
sed -i 's#3307#3309#g' /data/3309/my.cnf

#初始化数据
mysqld --initialize-insecure  --user=mysql --datadir=/data/3307/data --basedir=/opt/mysql
mysqld --initialize-insecure  --user=mysql --datadir=/data/3308/data --basedir=/opt/mysql
mysqld --initialize-insecure  --user=mysql --datadir=/data/3309/data --basedir=/opt/mysql

启动服务

#授权操作
chown -R mysql.mysql /data/*
#启动操作
mysqld_safe --defaults-file=/data/3307/my.cnf &
mysqld_safe --defaults-file=/data/3308/my.cnf &
mysqld_safe --defaults-file=/data/3309/my.cnf &

测试

netstat -lnp|grep 330

mysql -S /data/3307/mysql.sock
mysql -S /data/3308/mysql.sock
mysql -S /data/3309/mysql.sock

system管理多实例

cat >> /etc/systemd/system/mysqld3307.service <<EOF
[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
ExecStart=/opt/mysql/bin/mysqld --defaults-file=/data/3307/my.cnf
LimitNOFILE = 5000
EOF

#复制此文件到其它实例3308/3309
cp  /etc/systemd/system/mysqld3307.service   /etc/systemd/system/mysqld3308.service 

cp  /etc/systemd/system/mysqld3307.service   /etc/systemd/system/mysqld3309.service 

sed -i 's#3307#3308#g'   /etc/systemd/system/mysqld3308.service

sed -i 's#3307#3309#g'   /etc/systemd/system/mysqld3309.service

启动

systemctl start mysqld3307
systemctl stop mysqld3309
systemctl enable  mysqld3307

忘记密码处理

mysqladmin -uroot -p password 123

select user,authentication_string,host from mysql.user;

1.停数据库
/etc/init.d/mysqld stop
2.启动数据库为无密码验证模式
mysqld_safe --skip-grant-tables --skip-networking  &
update mysql.user set authentication_string=PASSWORD('456') where user='root' and host='localhost';
/etc/init.d/mysqld restart

mysql -uroot -p123
mysql -uroot -p456

数据类型和字符集

整型
	int 最多存10位数据
字符串类型
	char 定长,存储数据效率高,对于变化较多的字段,空间浪费较多
	varchar 变长,存储时判断长度,存储会有额外开销,按需分配存储空间
	enum
时间类型
	datetime
	timestamp
	date
	time

规范

1.少于10位的数字int,大于10位数 char
2.char和varchar选择时,字符长度一定不变的可以使用插入,可变的尽量使用varchar,在可变长度的存储时,将来使用不同的数据类型,对于索引树的高度是有影响的
3.选择合适的数据类型
4.合适长度

索引及执行计划

作用:优化查询,select查询有三种情况:缓存查询,全表扫描,索引扫描

索引种类

Btree(btree b+tree b*tree)
Rtree
HASH
FullText

b+tree原理图

Btree索引分类

聚集索引:基于主键,自动生成的,一般是建表时创建主键.如果没有主键,自动选择唯一索引作为主键索引(PRI)
辅助索引:人为创建的(MUL)
唯一索引:人为创建(普通索引,聚集索引)

聚集索引和辅助索引的区别

1.聚集索引:叶子节点,按照主键列的顺序,存储整行数据,就是真正的数据页
2.辅助索引:叶子节点,排序之后,存储到叶子节点+对应的主键的值,便于回表查询

创建索引

创建普通辅助索引(MUL)
alter table blog_userinfo add key idx_email(email);
create index idx_phone on blog_userinfo(phone);
查看索引
desc blog_userinfo;
show index from blog_userinfo;
删除索引
alter table blog_userinfo drop index idx_email;
drop index idx_phone on   blog_userinfo;

前缀索引

select count(*),substring(password,1,20) as sbp  from blog_userinfo group by sbp;
alter table blog_userinfo add index idx(password(10));


唯一键索引(如果有重复值就无法创建)
alter table blog_userinfo add unique key uni_email(email);
覆盖索引(联合索引)
	作用:不需要回表查询,不需要聚集索引,所有查询的数据都是从辅助索引中获取
select * from  people   where   gender ,  age ,  money
        
alter table t1 add index idx_gam(gender,age,money);

索引扫描性能

explain(desc)

type:查询 类型(越向下,性能越好)

ALL:全表扫描
Index:全索引索引
	desc select county from city;
range:索引范围扫描
	where > < 
	in or between and
	like 'CH%'
ref:辅助索引的等值查询
	in 或者 or 改写成 union
	select * from city where country = 'CHN'
	union all
	select * from city where country = 'USA'
eq_ref:多表连接查询
const,system:主键或者唯一键等值查询

Extra:

​ using filesort: 文件排序(建立联合索引)

建立索引的原则

(1) 必须要有主键,如果没有可以做为主键条件的列,创建无关列
(2) 经常做为where条件列   order by  group by   join on的条件(业务:产品功能+用户行为)
(3) 最好使用唯一值多的列作为索引,如果索引列重复值较多,可以考虑使用联合索引
(4) 列值长度较长的索引列,我们建议使用前缀索引.
(5) 降低索引条目,一方面不要创建没用索引,不常使用的索引清理,percona toolkit 
(6) 索引维护要避开业务繁忙期

不走索引的情况(开发规范)

1) 没有查询条件,或者查询条件没有建立索引 

	select * from tab;   全表扫描。
	select  * from tab where 1=1;
2) 查询结果集是原表中的大部分数据,应该是25%以上。
3) 索引本身失效,统计数据不真实
4) 查询条件使用函数在索引列上,或者对索引列进行运算,运算包括(+,-,*,/,! 等) 
例子: 
错误的例子:select * from test where id-1=9; 
正确的例子:select * from test where id=10;
5)隐式转换导致索引失效.这一点应当引起重视.也是开发中经常会犯的错误. 
	select * from t1 where telnum=110;

压力测试

1、模拟数据库数据
为了测试我们创建一个oldboy的库创建一个t1的表,然后导入50万行数据,脚本如下:
vim slap.sh
#!/bin/bash  
HOSTNAME="localhost" 
PORT="3306" 
USERNAME="root" 
PASSWORD="123" 
DBNAME="oldboy" 
TABLENAME="t1" 
#create database 
mysql -h ${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} -e "drop database if exists ${DBNAME}" 
create_db_sql="create database if not exists ${DBNAME}" 
mysql -h ${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} -e "${create_db_sql}" 
#create table 
create_table_sql="create table if not exists ${TABLENAME}(stuid int not null primary key,stuname varchar(20) not null,stusex char(1)   
not null,cardid varchar(20) not null,birthday datetime,entertime datetime,address varchar(100)default null)" 
mysql -h ${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} ${DBNAME} -e "${create_table_sql}" 
#insert data to table 
i="1" 
while [ $i -le 500000 ]  
do  
insert_sql="insert into ${TABLENAME}  values($i,'alexsb_$i','1','110011198809163418','1990-05-16','2017-09-13','oldboyedu')" 
mysql -h ${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} ${DBNAME} -e "${insert_sql}" 
let i++  
done  
#select data  
select_sql="select count(*) from ${TABLENAME}" 
mysql -h ${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} ${DBNAME} -e "${select_sql}"

执行脚本:
sh slap.sh


2、检查数据可用性
mysql -uroot -p123
select count(*) from oldboy.t1;

3、在没有优化之前我们使用mysqlslap来进行压力测试
mysqlslap --defaults-file=/etc/my.cnf \
 --concurrency=100 --iterations=1 --create-schema='oldboy' \
--query="select * from oldboy.t1 where stuname='alexsb_100'" engine=innodb \
--number-of-queries=2000 -uroot -p123 -verbose

存储引擎

作用:和磁盘打交道

简介

MySQL 基于存储引擎管理 表空间数据文件

种类:

Innodb存储引擎

	ibd:存储表的数据行和索引

	frm:表结构信息

Myisam存储引擎

	frm

	myi

	myd

事务

ACID特性
Atomic(原子性)
所有语句作为一个单元全部成功执行或全部取消
Consistent(一致性)
如果数据库在事务开始时处于一致状态,则在执行该事务期间将保留一致状态
Isolated(隔离性)
事务之间不相互影响
两个方面:修改同一行 , 一致性读
Durable(持久性)
事务成功完成后,所做的所有更改都会准确地记录在数据库中.所做的更改不会丢失.

行级锁:事务修改行,会锁定这行(持有这行的锁)

隔离级别(一致性读):
RU
RC
RR(默认)
S

事务控制语句

begin;
xxx
xxx
commit;

begin;
xxx
xxx

begin;
xxx
xxx
rollback;

隐式提交

set autocommit = 0 ;

日志

错误日志:

log_errot = /var/log/mysql.log

二进制日志

作用:
	记录所有变更类的语句
	DDL,DCL:以语句方式(statement)记录
	DML:默认是以行模式(row)记录
	可以做数据库审计
配置方法:
	log_bin = /opt/mysql/data/mysql-bin
	binlog_format =row
	server_id = 6
	sync_binlog =1
分析和截取日志
	#查看可以使用的二进制日志
	show binary logs;
	#正在使用的日志
	show master status;
	#查看二进制日志
	mysqlbinlog --base64-output=decode-rows -vvv /opt/mysql/data/mysql-bin.000005
	

慢日志

记录慢语句的日志文件
slow_query_log = 1
slow_query_log_file = /opt/mysql/data/standby-slow.log
#记录时间超过0.1秒的语句
long_query_time = 0.1
#记录不走索引的语句
log_queries_not_using_indexes=1

备份恢复

备份的种类

逻辑备份:SQL语句的备份
物理备份:数据页备份

逻辑备份工具介绍

	
	   select xxxx from t1  into outfile '/tmp/redis.txt'
	   
	 mysql -uroot -p123 -e "select concat('hmset city_',id,' id ', id,' name ',name,' countrycode ',countrycode,' district ',district,' population ',population) from world.city limit 10 "|redis-cli
	 
mysqldump

-A全部备份
mysqlddump -uroot -p123 -A >/backup/a.sql
-B选择指定的数据库备份
mysqlddump -uroot -p123 -B world bbs >/backup/a.sql
只备份单库或者库中的表
mysqldump -uroot -p123 >/backup/ccc.sql
--master-data =2 备份时记录二进制日志的状态
--single-transaction 开启innodb热备功能
-R
--triggers

导出一行

select * from city where id = 1 into outfile '/tmp/redis.txt'

主从复制

​ 基于二进制日志的结构

前提需要有两台服务器,或者在在一台服务器上开启了多实例
设置主机与从机:Master为3307,slave为3308
3307中创建复制用户
主库开启二进制日志
#在mysql的配置文件中添加log_bin=/data/3307/mysql-bin
vim /data/3307/my.cnf 
log_bin=/data/3307/mysql-bin
#重启mysql数据库服务
systemctl restart mysqld3307
#进入数据库命令行
mysql -S /data/3307/mysql.sock
#设置密钥(在数据库的命令行下操作)
grant replication slave on *.* to repl@'10.0.0.%' identified by '123';
#查看密钥
 show master status;

创建从机

#进入数据库
mysql -S /data/3308/mysql.sock
mysql> CHANGE MASTER TO
  MASTER_HOST='10.0.0.200',
  MASTER_USER='repl',
  MASTER_PASSWORD='123',
  MASTER_PORT=3307,
  MASTER_LOG_FILE='mysql-bin.000001',
  MASTER_LOG_POS=154;

mysql> start slave;
#若显示下列则表示成功
Slave_IO_Running: Yes
Slave_SQL_Running: Yes

"高可用"架构

​ 99%

​ 99.9%

​ 99.99%

​ 99.999%

MySQL高可用架构

MHA
PXC
galera cluster


"高性能架构"

​ 读写分离

atlas 360  C++
maxscale  mariadb
proxysql
DRDS
mysql router

​ 分布式架构

分片集群
TDDL
mycat
DBLE
DRDS

posted @ 2019-01-15 20:15  周建豪  阅读(178)  评论(0编辑  收藏  举报