MySQL进阶

一、MySQL的多实例安装

以前一些很low的方法就是解压两个mysql,分别放到不同的文件夹。其实mysql已经考虑到了多实例的安装情况,也有相应的脚本命令的支持。

现需要装两个mysql,一个3307,一个3308。

1、新建/etc/my.cnf配置如下

[mysqld]
sql_mode = "STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER"
 
[mysqld_multi]
mysqld = /usr/local/mysql/bin/mysqld_safe
mysqladmin = /usr/local/mysql/bin/mysqladmin
log = /var/log/mysqld_multi.log
 
[mysqld1] 
server-id = 11
socket = /tmp/mysql.sock1
port = 3307
datadir = /data1
user = mysql
performance_schema = off
innodb_buffer_pool_size = 32M
skip_name_resolve = 1
log_error = error.log
pid-file = /data1/mysql.pid1
[mysqld2]
server-id = 12
socket = /tmp/mysql.sock2
port = 3308
datadir = /data2
user = mysql
performance_schema = off
innodb_buffer_pool_size = 32M
skip_name_resolve = 1
log_error = error.log
pid-file = /data2/mysql.pid2

2、创建2个数据目录

mkdir /data1
mkdir /data2
chown mysql.mysql /data{1..2}
mysqld --initialize --user=mysql --datadir=/data1
mysqld --initialize --user=mysql --datadir=/data2
cp /usr/local/mysql/support-files/mysqld_multi.server /etc/init.d/mysqld_multid

3、配置开机启动

chkconfig mysqld_multid on

查看状态

mysqld_multi report

这时发现还需要perl的环境,安装

yum -y install perl perl-devel

在运行,发现已经有实例了

mysqld_multi report
mysqld_multi start

4、启动,分别修改密码,允许远程连接

mysql -u root -S /tmp/mysql.sock1 -p -P3307
mysql -u root -S /tmp/mysql.sock1 -p -P3308
set password='root1234%';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root1234%';
flush privileges;

二、MySQL权限

使用Root用户执行以下SQL语句,则创建了一个user1的用户,密码为123456,仅仅运行在网段为192.168.20.*的网段对test01里面的表只有查询权限

grant SELECT on test01.* TO 'user1'@'192.168.20.%' IDENTIFIED BY '123456' WITH GRANT OPTION;

再执行以下命令查看user1用户的权限,它就只能执行select的操作。

show grants for 'user1'@'192.168.20.%

1、用户标识

mysql中的权限是赋予给“用户+IP”的。

2、用户权限所涉及的表

mysql.user的一行记录代表一个用户标识

mysql.db的一行记录代表对数据库的权限

mysql.table_priv的一行记录代表对表的权限

mysql.column_priv的一行记录代表对某一列的权限

-- 新建一个user表
CREATE TABLE `user` (
`id` int(11) NOT NULL, `name` varchar(50) DEFAULT NULL, `age` int(255) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_age` (`age`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 插入几条数据
INSERT INTO `user` VALUES ('1', 'aa', '10');
INSERT INTO `user` VALUES ('2', 'bb', '15');
INSERT INTO `user` VALUES ('3', 'cc', '18');
INSERT INTO `user` VALUES ('5', 'ee', '20');

对于前面创建的user1用户不想让他看到age列,但是可以查询id,name

grant select(id,name) on test01.user to 'user1'@'192.168.20.%'

三、MySQL架构

1、mysql的连接

当MySQL启动(MySQL服务是一个进程),等待客户端连接,每一个客户端连接请求,服务器都会新建一个线程处理(线程池分配一个空的线程),每个线程独立,拥有各自的内存处理空间。客户端连接到服务器,服务器需要对其验证,也就是用户名,IP,密码的验证,一旦连接成功,还要验证是否具有执行某个特定查询的权限(是否允许客户端对某个数据库,某个表的某个操作)

show VARIABLES like '%max_connections%';

在这里插入图片描述

2、mysql解析优化

以下sql语句在执行时in查询会被优化成join查询

select * from user t where t.id in (select t2.id from user t2)

在这里插入图片描述

3、查看数据库的数据库存放位置

show VARIABLES like 'datadir'

在这里插入图片描述

我们创建一个数据库后,会在上面的datadir目录新建一个子文件夹,用户建立的表都会在子文件夹下面,它和具体的存储引擎相关,但有个共同的就是都有个frm文件,它存放的是表的数据格式。
在这里插入图片描述

4、mysql utilities 安装

tar -zxvf mysql-utilities-1.6.5.tar.gz 
cd mysql-utilities-1.6.5 
python ./setup.py build 
python ./setup.py install

在这里插入图片描述

安装完mysql utilities就可以使用mysqlfrm命令查看表的数据结构了

mysqlfrm --diagnostic /data/mysql/test/user.frm

在这里插入图片描述

5、存储引擎

查看mysql现在已提供什么存储引擎

show engines;

在这里插入图片描述
查看mysql当前默认的存储引擎

show variables like '%storage_engine%';

在这里插入图片描述

5.1、存储引擎:MyISAM

MySQL5.5之前默认的存储引擎,MyISAM存储引擎由MYD和MYI组成

创建一个MyISAM存储引擎的表

CREATE TABLE `testmysam` (
`id` int(11) NOT NULL, `name` varchar(50) DEFAULT NULL, `age` int(255) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_age` (`age`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

在这里插入图片描述
表压缩

myisampack -b -f /data/mysql/test/testmysam.MYI

压缩后再往表里面新增数据就新增不了啦,压缩后,需要

myisamchk -r -f /data/mysql/test/testmysam.MYI

MyISAM主要适用的场景:非事务型应用(数据仓库,报表,日志数据等)、只读类应用,空间类应用(空间函数,坐标),由于Innodb越来越强大,MyISAM已经停止的维护。

5.2、存储引擎:Innodb

Innodb是一种事务性存储引擎,完全支持事务的ACID特性,Innodb还支持行级锁(并发程度更高)

5.3、存储引擎:CSV

以csv格式进行数据存储,所有列都不能为null,不支持索引,可以对数据文件直接编辑

--创建一个csv存储引擎的表
create table mycsv(id int not null,c1 VARCHAR(10) not null,c2 char(10) not null) engine=csv;
-- 插入数据
insert into mycsv values(1,'aaa','bbb'),(2,'cccc','dddd');

在这里插入图片描述

修改csv文件

vi /data/mysql/test/mycsv.CSV 
flush TABLES; 
select * from mycsv

在这里插入图片描述
在这里插入图片描述

6、MySQL中的锁

表级锁:开锁小,加锁快,不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

行级锁:开锁大,加锁慢,会出现死锁;锁定粒度小,发生锁冲突的概率最低,并发度也最高。

页面锁(gap锁,间隙锁):开锁和加锁时间界于表锁和行锁之间;会出现死锁,锁定粒度界于表锁和行锁之间,并发度一般。

使用场景:

表级锁更适合于以查询为主,和只有少量按索引条件更新数据的应用。如OLAP系统。

行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如一些在线事务处理(OLTP)系统。

MySQL的表级锁有两种模式:表共享读锁、表独占写锁

6.1、MyISAM锁

读锁:对MyISAM表的读操作,不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的写请求。

读锁:对MyISAM表的读操作,不会阻塞当前session对表读,当对表进行修改会报错

读锁:一个session使用LOCK TABLE命令给表f加了读锁,这个session可以查询锁定表中的记录,但更新或访问其他表都会提示错误

写锁:对MyISAM表的写操作,则会阻塞其他用户对同一表的读和写操作;

写锁:对MyISAM表的写操作,当前session可以对本表做CRUD,但对其他表进行操作会报错

6.2、InnoDB锁

在mysql的InnoDB引擎支持行锁

共享锁又称读锁,当一个事务对某几行上读锁时,允许其他事务对这几行进行读操作,但不允许其进行写操作,也不允许其他事务给这几行上排它锁,但允许上读锁。

排它锁又称写锁,当一个事务对某几个上写锁时,不允许其他事务写,但允许 读,更不允许其他事务给这几行上任何锁,包括写锁。

语法:

-- 上共享锁的写法
lock in share mode
例:select * from 表名 where 条件 lock in share mode;
-- 上排它锁的写法
for update
例:select * from 表名 where 条件 for update;

注意:

两个事务不能锁同一个索引;

insert,delete,update在事务中都会自动默认加上排它锁;

行锁必须有索引才能实现,否则会自动锁全表,那么就不是行锁了。

表锁lock table testdemo WRITE
使用 commit,ROLLBACK 并不会解锁
使用 UNLOCK TABLES 或者 begin 会解锁

锁的等待问题:

在工作中经常会遇到一个数据被锁住,导致另外的操作完全进行不下去。

select * from information_schema.INNODB_LOCKS;

在这里插入图片描述
通过上面的sql语句可以发现在同一张表里面的同一个数据有了2个锁,X(写锁)、S(读锁),这时我们可以跳过这条数据,用其它数据做调试。如果 一定要用这条数据,查询被锁的数据

select * from sys.innodb_lock_waits

在这里插入图片描述
在这里插入图片描述

可以直接把阻塞的sql语句给干掉: kill 91

如果是5.6的版本没有sys库,这时就需要用到下面的sql查询出blocking_thread,然后kill 掉。

SELECT r.trx_id waiting_trx_id,
r.trx_mysql_thread_id waiting_thread, r.trx_query waiting_query, b.trx_id blocking_trx_id, b.trx_mysql_thread_id blocking_thread FROMinformation_schema.innodb_lock_waits w INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;

7、MySQL中的事务

查看某张表的存储引擎

show create table 表名 ;

在这里插入图片描述
对于表的存储结构的修改

建立InnoDB表:
Create table .... type=InnoDB;
Alter table table_name type=InnoDB;

事务的特性:原子性,一致性,隔离性,持久性,这四个属性被称为ACID特性。

7.1、原子性(atomicity)

整个事务中的所有操作要么全部提交成功,要么全部提交失败,对于一个事务来说,不可能只执行其中的一部分操作。

比如:A账户扣500 与 B账户加500元,要么全部成功,要么全部失败

7.2、一致性(consistency)

一致性是指事务将数据库从一种一致性转换到另一种一致性状态,在事务开始之前和事务结束之后数据库中数据的完整性没有被破坏。

比如:A账户扣500 与 B账户加500元 一致,两者相加为0

7.3、持久性(durability)

一旦事务提交,则其所做的修改就会永久保存到数据库中,此时即使系统崩溃,已经提交的修改数据也不会丢失。

这一点并不是数据库的角度完全能解决的。

7.4、隔离性(isolation)

一个事务的执行,不能被其他事务干扰。即一个事务内部的操作与使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

mysql的事务隔离级别:

  • 未提交读(READ UNCOMMITED)脏读

  • 已提交读 (READ COMMITED)不可重复读

  • 可重复读(REPEATABLE READ)

  • 可串行化(SERIALIZABLE)

mysql默认的隔离级别为:可重复读(REPEATABLE READ)
在这里插入图片描述

事务并发的问题:

脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据就是脏数据

不可重复读:事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。

幻读:A用户把数据库中的成绩从具体分数改为ABCDE等级,但是B用户在这个时候又插入了一条分数记录,这时A改完结果后发现还有一条记录没有改过来,就像幻觉一样,这就是幻读。

不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需要锁住满足条件上的行,解决幻读需要锁表。

间隙锁(gap锁)

在MySQL中,可重复读已经解决了幻读的问题,用的就是间隙锁。

select @@tx_isolation; create table t_lock_1 (a int primary key); insert into t_lock_1 values(10),(11),(13),(20),(40); begin select * from t_lock_1 where a <= 13 for update; 
在另外一个会话中 
insert into t_lock_1 values(21) 成功 
insert into t_lock_1 values(19) 阻塞

在rr隔离级别中,会扫描到当前值13的下一个值20,并把这些数据全部加锁。

create table t_lock_2 (a int primary key,b int, key (b)); insert into t_lock_2 values(1,1),(3,1),(5,3),(8,6),(10,8); 
会话 1 
BEGIN select * from t_lock_2 where b=3 for update;
会话 2
select * from t_lock_2 where a = 5 lock in share mode; -- 不可执行,因为 a=5 上有一把记录锁 
insert into t_lock_2 values(4, 2); -- 不可以执行,因为 b=2 在(1, 3]内 
insert into t_lock_2 values(6, 5); -- 不可以执行,因为 b=5 在(3, 6)内 
insert into t_lock_2 values(2, 0); -- 可以执行,(2, 0)均不在锁住的范围内 
insert into t_lock_2 values(6, 7); -- 可以执行,(6, 7)均不在锁住的范围内 
insert into t_lock_2 values(9, 6); -- 可以执行 
insert into t_lock_2 values(7, 6); -- 不可以执行

1 3 5 8 10

1 1 3 6 8

二级索引锁住b的范围是(1,3],(3,6)

主键索引只锁住了a=5的这条记录。

事务的语法

1、开启事务

(1)begin

(2)START TRANSACTION(推荐)

(3)begin work

2、事务回滚:rollback

3、事务提交:commit

4、还原点

savepoint 
show variables like '%autocommit%'; 自动提交事务是开启的
set autocommit=0; 
insert into testdemo values(5,5,5); 
savepoint s1; 
insert into testdemo values(6,6,6); 
savepoint s2; 
insert into testdemo values(7,7,7); 
savepoint s3;
select * from testdemo 
rollback to savepoint s2 
rollback 

四、数据库的逻辑设计

1、范式设计

(1)数据库表中的所有字段都只具有单一属性

例如以下设计:name-age列具有两个属性,不符合第一范式,需把它拆分成两列。
在这里插入图片描述

(2)表中只具有一个业务主键。

例如以下设计:不符合第二范式,需把计单表拆分为订单表和订单与商品中间表
在这里插入图片描述

(3)每一个非非主属性即不部分依赖于也不全部依赖于业务主键

例如以下设计:客户编号改变,客户性名也会改变,这样不符合第三大范式,应该把客户姓名这一列删除
在这里插入图片描述

2、反范式设计

反范式是为了性能和读取效率的考虑而适当的对数据库设计范式的要求进行违反。允许存在少量的冗余,换句话说就是使用空间来换取时间。

范式化设计优缺点:

优点:可以尽量的减少数据冗余,更新操作比范式化更快,表通常比反范式化的表更小

缺点:对于查询需要对多个表进行关联,更难进行索引优化

反范式化设计优缺点:

优点:可以减少表的关联,可以更好的进行索引优化

缺点:存在数据冗余及数据维护异常,对数据的修改需要更多的成本

五、慢查询

慢查询日志是指mysql记录所有执行超过long_query_time参数设定的时间阈值的SQL语句的日志。该日志能为SQL语句的优化带来很好的帮助。默认情况下,慢查询日志是关闭的,要使用慢查询日志功能,首先要开启慢查询日志。

1、慢查询的基本配置

slow_query_log 启动停止技术慢查询日志

slow_query_log_file 指定慢查询日志得存储路径及文件(默认和数据文件放一起)

long_query_time 指定记录慢查询日志 SQL 执行时间得伐值(单位:秒,默认 10 秒)

log_queries_not_using_indexes 是否记录未使用索引的 SQL

log_output 日志存放的地方【TABLE】【FILE】【FILE,TABLE】

配置了慢查询后,它会记录符合条件的SQL

包括查询语句、数据修改语句、已经回滚的SQL

通过下面命令可以查看上面的配置

show VARIABLES like '%slow_query_log%' 
show VARIABLES like '%slow_query_log_file%' 
show VARIABLES like '%long_query_time%' 
show VARIABLES like '%log_queries_not_using_indexes%' 
show VARIABLES like 'log_output'

---默认 10 秒,这里为了演示方便设置为 0
set global long_query_time=0;  
--开启慢查询日志
set GLOBAL slow_query_log = 1;  
--项目开发中日志只能记录在日志文件中,不能记表中
set global log_output='FILE,TABLE' 

在这里插入图片描述

设置完以上参数后,查询一些列表可以发现慢查询的日志文件里已经有数据了

cat /data/mysql/VM-4-12-centos-slow.log

在这里插入图片描述
在这里插入图片描述

解读以上慢查询格式显示

第一行:用户名,用户的IP信息,线程ID号
第二行:执行花费的时间(毫秒),执行获得锁的时间,获取结果的行数,扫描的数据行数
第三行:SQL执行的具体时间
第四行:具体的SQL语句

慢查询的日志记录非常多,要从里面找寻一条查询慢的日志还需要一些辅助工具才能快速定位到需要优化的SQL语句,下面有两个慢查询的辅助工具:

(1)Mysqldumpslow

mysqldumpslow -s r -t 10 VM-4-12-centos-slow.log
-s order (c,t,l,r,at,al,ar) 
c:总次数 
t:总时间 
l:锁的时间 
r:总数据行 
at,al,ar :t,l,r 平均数 【例如:at = 总时间/总次数】 
-t top 指定取前面几天作为结果输出

mysqldumpslow -s t -t 10 /data/mysql/VM-4-12-centos-slow.log

在这里插入图片描述
出现这个错误是因为系统默认会查找/usr/bin下的命令,由于mysqldumpslow没有在这个目录下,所以会出现command not found

解决方法:只需要把mysql安装目录的该文件,软连接到/usr/bin目录下就可以使用了。

ln -s /usr/local/mysql/bin/mysqldumpslow /usr/bin

在这里插入图片描述
(2)pt_query_digest

pt_query_digest也是用于分析mysql慢查询的一个工具,与mysqldumpshow工具相比,pt_query_digest工具的分析结果更具体,更完善。。。

六、索引与执行计划

1、数据结构

索引相关于我们一本书的目录,可以快速查询到目录里面的内容,它能高效获取数据,是高效获取数据的数据结构。

再例如我们去图书馆找一本书,图书馆的书肯定不是线性存放的,它对不同的书籍内容进行了分类存放,整个索引由一个个节点组成,根节点有中间节点,中间节点下面又有子节点,最后一层是叶子节点。相当于一棵倒挂着的树,其实它就是一种数据结构,这种数据结构比前面的线性目录更好的增加了查询速度。

二分查找法(binary search)

也称为折半查找法,用来查找一组有序的记录数组中的某一记录。
基本思想是:将记录按有序化(递增或递减)排列,在查找过程中采用跳跃式方式查找,即先以有序数列的中点位置作为比较对象,如果要找的元素值小于该中点元素,则将待查序列缩小为左半部分,否则为右半部分。通过一次比较,将查找区间缩小一半。

二叉树(Binary Tree)

每个节点至多只有二棵子树

  • 二叉树的子树有左右之分,次序不能颠倒;

  • 一棵深度为 k,且有 个节点,称为满二叉树(Full Tree);

  • 一棵深度为 k,且 root 到 k-1 层的节点树都达到最大,第 k 层的所有节点都 连续集中 在 最左边,此时为完全二叉树(Complete Tree)
    在这里插入图片描述

平衡二叉树(AVL-树)

  • 左子树和右子树都是平衡二叉树;

  • 左子树和右子树的高度差绝对值不超过 1;
    在这里插入图片描述

需要通过旋转(左旋,右旋)来维护平衡二叉树的平衡,在添加和删除的时候需要有额外的开销。

B+树

  • 所有记录都存储在叶子节点上,非叶子(non-leaf)存储索引(keys)信息;

  • B+树含有非常高的扇出(fanout),通常超过 100,在查找一个记录时,可以有效的减少 IO 操作;

  • 叶子节点本身按照数据的升序排序进行链接(串联起来);
    在这里插入图片描述
    该 B+ 树高度为 2

每叶子页(LeafPage)4 条记录

扇出数为 5

叶子节点(LeafPage)由小到大(有序)串联在一起

扇出 是每个索引节点(Non-LeafPage)指向每个叶子节点(LeafPage)的指针

扇出数 = 索引节点(Non-LeafPage)可存储的最大关键字个数 + 1

图例中的索引节点(Non-LeafPage)最大可以存放 4 个关键字,但实际使用了 3 个

B+树的插入操作

B+树的插入必须保证插入后叶子节点中的记录依然排序
在这里插入图片描述

2、MySQL的索引

(1)、索引的分类

普通索引:即一个索引只包含单个列,一个表可以有多个单列索引

**唯一索引:**索引列的值必须唯一,但允许有空值,而主键索引是不允许有空值的

**复合索引:**即一个索引包含多个列

**聚簇索引(聚集索引):**并不是一种单独的索引类型,而是一种数据存储方式,具体细节取决于不同的实现,InnoDB的聚簇索引其实就是在同一个结构中保存了B+Tree索引和数据行。

**非聚簇索引:**不是聚簇索引。

(2)、基础语法

查看索引

SHOW INDEX FROM 表名

在这里插入图片描述
创建索引

CREATE [UNIQUE ] INDEX indexName ON mytable(columnname(length)); 
ALTER TABLE 表名 ADD [UNIQUE ] INDEX [indexName] ON (columnname(length))

删除索引

DROP INDEX [indexName] ON mytable;

3、执行计划

使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MYSQL是如果处理你的SQL言不顺句,分析你的查询语句或是表结构的性能瓶颈。

执行计划的作用:

表的读取顺序(id)

数据读取操作的操作类型(select_type)

哪些索引可以使用(possible_keys)

哪些索引被实际使用(key)

表之间的引用(ref)

每张表有多少行被优化器查询(row)

执行计划的语法:

在 SQL 查询的前面加上 EXPLAIN 关键字就行。

EXPLAIN SELECT * FROM testdemo

在这里插入图片描述

(1)id列:

描述select查询的序列号,相同从上往下执行,id不同的id越大越先执行

(2)select_type列:

查询的类型
用于区别:普通查询、联合查询、子查询等的复杂查询
在这里插入图片描述
SIMPLE
在这里插入图片描述

PRIMARY SUBQUERY

PRIMARY:查询中若包含任何复杂的子部分,最外层查询则被标记为

SUBQUERY:在select或where列表中包含了子查询
在这里插入图片描述
DERIVED

在from列表中包含的子查询被标记为DERIVED(衍生)

MySQL会递归执行这些子查询,把结果放在临时表里。
在这里插入图片描述

UNION RESULT与 UNION

UNION:若第二个 SELECT 出现在 UNION 之后,则被标记为 UNION;

UNION RESULT:从 UNION 表获取结果的 SELECT
在这里插入图片描述

(3)table列

显示这一行的数据是关于哪张表的

(4)type列

type显示的是访问类型,是较为重要的一个指标,结果值从最好到最坏依次是:

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

需要记的是:system>const>eq_ref>ref>range>index>ALL

一般来说,得保证查询至少达到range级别,最好能达到ref

System:表示只有一行记录

Const:表示通过索引一次就找到了

eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描

ref:非唯一性索引扫描,返回匹配某个单独值的所有行

range:只检索给定范围的行,使用一个索引来选择行。key 列显示使用了哪个索引,一般就是在你的 where 语句中出现了 between、<、>、in 等的查询这种范围扫描索引扫描比全表扫描要好,因为它只需要开始于索引的某一点,而结束语另一点,不用扫描全部索引。

index:当查询的结果全为索引列的时候,虽然也是全部扫描,但是只查询的索引库,而没有去查询数据

all:将遍历全表以找到匹配的行

(5)possible_keys与key列

possible_keys:可能使用的 key

Key:实际使用的索引。如果为 NULL,则没有使用索引

查询中若使用了覆盖索引,则该索引和查询的 select 字段重叠

(6)key_len列

Key_len 表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。在不损失精 确性的情况下,长度越短越好

key_len 显示的值为索引字段的最大可能长度,并非实际使用长度,即 key_len 是根据表定义计算而得,不是通过表内检索出的

  • key_len 表示索引使用的字节数,

  • 根据这个值,就可以判断索引使用情况,特别是在组合索引的时候,判断所有的索引字段是否都被查询用到。

  • char 和 varchar 跟字符编码也有密切的联系,

  • latin1 占用 1个字节,gbk占用2个字节,utf8占用3个字节。(不同字符编码占用的存储空间不同)

**字符类型:**变长字段需要额外的 2 个字节(VARCHAR 值保存时只保存需要的字符数,另加一个字节来记录长度(如果列声明的长度超过 255,则使用两个字节),所以 VARCAHR 索引长度计算时候要加 2),固定长度字段不需要额外的字节。

而 NULL 都需要 1 个字节的额外空间,所以索引字段最好不要为 NULL,因为 NULL 让统计更加 复杂并且需要额外的存储空间。

复合索引有最左前缀的特性,如果复合索引能全部使用上,则是复合索引字段的索引长度之和,这也可以用来判定复合索引是否部分使用,还是全部使用。

**整数/浮点数/时间类型的索引长度:**NOT NULL=字段本身的字段长度

NULL=字段本身的字段长度+1(因为需要有是否为空的标记,这个标记需要占用 1个字节)

datetime 类型在 5.6 中字段长度是 5 个字节,datetime 类型在 5.5 中字段长度是 8 个字节

(7)ref列

显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值

(8)rows列

根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数

(9)Extra

包含不适合在其他列中显示但十分重要的额外信息。
在这里插入图片描述

(10)Using filesort

说明 mysql 会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。 MySQL 中无法利用索引完成的排序操作称为“文件排序”

当发现有 Using filesort 后,实际上就是发现了可以优化的地方

(11)Using temporary

使用的临时表保存中间结果,MySQL在对查询结果排序时使用临时表,常见于排序order by和分组查询group by

如发现执行计划里有 using filesort而且还有 using temporary的时候,需要注意了。

(12)覆盖索引 :

索引是高效找到行的一个方法,但是一般数据库也能使用索引找到一个列的数据,因此它不必读取整个行,毕竟索引叶子节点存储了它们索引的数据,当能通过读取索引就可以得到想要的数据,那就不需要读取行了,一个索引包含了满足查询结果的数据就叫做覆盖索引。

如果要使用覆盖索引,一定要注意select列表中只取出需要的列,不可select *,因为如果将所有字段一起做索引会导致索引文件过大,查询性能下降。所以不能为了查询而在所有列上都建立索引,会严重影响修改维护的性能。

(13)Using where 与 using join buffer

Using where:表明使用了where过滤

using join buffer:使用了连接缓存

(14)impossible where

where子句的值总是false,不能用来获取任何元素

explain select * from t1 where 1=2

七、SQL优化

1、优化策略:

(1)尽量全值匹配:建立了索引列后,能在where条件中使用索引 的尽量使用

(2)最佳左前缀法则:如果索引了多列,要遵守最左前缀法则,指的是查询从索引的最左前列开始并且不跳过索引中的列

(3)不在索引列上做任何操作:不在索引列上做计算、函数、类型转换等操作,会导致索引失效而转向全表扫描

(4)范围条件放最后:如果中间有范围查询会导致后面的索引列全部失效

(5)覆盖索引尽量用:只访问索引的查询(索引列和查询列一致,减少select *

(6)不等于要甚用:mysql中使用不等于(!=或<>)的时候无法使用索引 会导致全表扫描,如果非要使用不等于,请用覆盖索引

(7)Null/Not 有影响:在字段为not null的情况下,使用is null 或 is not null会导致索引失效

(8)like查询要当心:like以通配符开头(‘%abc’)或(’%abc%’)mysql索引失效会变成全表扫描的操作,而(‘abc%’)索引不会失效

(9)字符类型加引号:字符串不加单引号索引失效

(10)OR改UNION效率高

八、批量导入

pom.xml文件中加入依赖

 <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>

在这里插入图片描述

insert语句优化

提交前关闭自动提交,尽量使用批量insert语句,可以使用MyISAM存储引擎

使用LOAD DATA INFLIE比一般的insert语句快20倍

select * into OUTFILE 'D:\\product.txt' from product_info

load data INFILE 'D:\\product.txt' into table product_info

load data INFILE '/soft/product3.txt' into table product_info

show VARIABLES like 'secure_file_priv'

secure_file_priv 为 NULL 时,表示限制 mysqld 不允许导入或导出。

secure_file_priv 为 /tmp 时,表示限制 mysqld 只能在/tmp 目录中执行导入导出,其他 目录不能执行。

secure_file_priv 没有值时,表示不限制 mysqld 在任意目录的导入导出。

%’)索引不会失效

(9)字符类型加引号:字符串不加单引号索引失效

(10)OR改UNION效率高

八、批量导入

pom.xml文件中加入依赖

 <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>

insert语句优化

提交前关闭自动提交,尽量使用批量insert语句,可以使用MyISAM存储引擎

使用LOAD DATA INFLIE比一般的insert语句快20倍

select * into OUTFILE 'D:\\product.txt' from product_info

load data INFILE 'D:\\product.txt' into table product_info

load data INFILE '/soft/product3.txt' into table product_info

show VARIABLES like 'secure_file_priv'

secure_file_priv 为 NULL 时,表示限制 mysqld 不允许导入或导出。

secure_file_priv 为 /tmp 时,表示限制 mysqld 只能在/tmp 目录中执行导入导出,其他 目录不能执行。

secure_file_priv 没有值时,表示不限制 mysqld 在任意目录的导入导出。

secure_file_priv=’’

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值