mysql查询优化

2019-04-24  本文已影响0人  Teemo_fca4
查询sql的数学表达

1 SELECT A.,B. //投影
FROM A,B //笛卡尔积
WHERE A.c1=1 AND B.c1=2 //选择
UNION //并集,差集
SELECT A.,B.
FROM A,B
WHERE A.c1=1 AND B.c1=2 OR B.c1>100

mysql 逻辑架构
MYISAM和InnoDB的主要区别
对比项 MYISAM InnoDB
外键 不支持 支持
事物 不支持 支持
缓存 只缓存索引,不缓存数据 既缓存索引,也缓存数据
表空间
关注点 性能 事物

mysql执行解析顺序图


mysql执行解析顺序图
7种join理论
image.png

以下面两张表做演示


学生表
老师表
左外连接效果:右边为空时,以null 补全。
image.png
左外连接,只保留自己独有的数据
image.png
右外连接效果:左边为空时,以null 补全。
image.png
右外连接,只保留自己独有的数据。
image.png
内连接,取交集。
image.png
或者如下
image.png
全连接:取并集。(因为mysql不支持full join,这里我们使用union实现)
image.png
全连接:取各自独有的部分。(因为mysql不支持full join,这里我们使用union实现)
image.png
索引
索引是一种已经排好序的快速查找数据结构
索引的类型
索引建立的原则
不适合建立索引的情况
使用explain来查看mysql的查询语句的执行计划,explain重要字段的解释

using FileSort只是对数据使用外部的索引排序,但是Using temporary会将排序后的结果缓存于创建的一张临时表中,然后再删除临时表,这种情况相比于sing filesort更差

所以如果要使用覆盖索引,一般只取select 需要的列 而不用select *,因为不可能所有字段都一起做索引的,其次 多余字段也会消耗不必要的网络IO。
JOIN优化,

CREATE TABLE class (
id int(11) NOT NULL AUTO_INCREMENT,
card int(255) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb4;

CREATE TABLE book (
bookid int(11) NOT NULL AUTO_INCREMENT,
card int(10) NOT NULL,
PRIMARY KEY (bookid)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb4;

建立以上两张表,各随机插入20条数据,
不建立索引时:两张表均全表扫描

ALTER TABLE book ADD INDEX Y(card);


image.png

ALTER TABLE book ADD INDEX Y(card);


image.png

我们知道ref的性能是优于index的,并且第二种情况扫描的行数更少,因此可以得出以下总结
连表(join)查询优化原则

    • 小表驱动大表
    • 左连接时索引应建在右表上(如果索引已经建立在左表上,那么换成右连接查询),右连接索引应建在左表上(如果索引已经建立在右表上,那么换成左连接查询),这是由左连接特性决定的,左连接时left join用于确定搜索右表数据,左表的数据一定有 所以我们需要将索引加在右表上,右连接则相反。
    • 调大join buffer设置
关于索引的一些原则
以下补充索引对于排序时使用的情况,以KEY(a,b,c)为例子

会使用索引排序,不会产生filesort的情况

条件 备注
order by a或者order by a,b或者order by a,b,c 符合最左前缀原则
order by a desc,b desc,c desc 方向一致并且符合最左前缀原则
where a= const order by b,c或者a=const and b=const order by c或者 a=const and b>const order by c 最左前缀为常量,则其后面的列相当于前缀,这种情况也没问题

不会使用索引排序,会产生filesort的情况

条件 备注
order by a desc,b asc,c desc 方向不一致
order by b,c或者order by a,c 不符合最左前缀原则
order by a,b,c,d d不是索引的列
where a in {...} order by b,c 对于排序来说,多个条件相当于范围查询,这种情况也不符合最左前缀原则
对于group by(先排序后分组)其原则与order by几乎一致,也是最左原则什么的,注意的是:能在where里面过滤的就没必要在having里过滤
一些常用法则
    • 读锁(共享锁):多个读操作之间可以同时进行,不会互相干扰
    • 写锁(排它锁):在当前写操作没完成前,会阻断其他写锁和读锁
    • 行锁(偏写):
    • 表锁(偏读):

对于myisam(表级锁,不支持事务):在执行查询语句(select)前,会自动给表加读锁,在执行写操作前会自动给表加写锁
myisam 读锁
LOCK TABLE book READ;
SELECT * from book where id =1 ; -- 可以查出结果
SELECT * FROM test2 where id =1 ; -- 不能查出其他表结果
INSERT INTO book VALUES (1,"1","1"); -- 读锁不能修改数据
UNLOCK TABLES ;
对于其他session
SELECT * from book where id =1 ; -- 可以查出结果
SELECT * FROM test2 where id =1 ; -- 可以查出结果
INSERT INTO book VALUES (1,"1","1"); -- 阻塞直到上面的读锁被释放
myisam 写锁
LOCK TABLE book WRITE;
SELECT * from book where id =1 ; -- 可以读取结果
INSERT INTO book VALUES (2,"2","2"); -- 可以更改数据
SELECT * FROM test2 where id =1 ; -- 不能获取其他表的数据
UNLOCK TABLES;
对于其他session
SELECT * FROM test2 where id =1 ; -- 可以查出结果
SELECT * from book where id =1 ; -- 阻塞 读写均阻塞

对于innodb(行级锁,支持事务)
session1
SET autocommit = 0; -- 取消自动提交
update people SET name = "a" WHERE id = 1; -- 更新1号记录
COMMIT; -- 提交
session2
SET autocommit = 0; -- 取消自动提交
UPDATE people SET name = "b" WHERE id = 2; -- 更新2号记录(因为innodb使用的是行锁,因此此时不阻塞)
COMMIT; -- 提交

注意
   innodb使用的是行锁,但是行锁会升级到表锁。使用行锁的前提是where后面使  用到索引,如果限制列没建立索引或者有索引但是未使用到,那么mysql的行锁将会升级到表锁。   
使用for update 来锁定select的行(使用的时候要注意加限制条件,避免锁全表)

session1
SET autocommit = 0; -- 取消自动提交
SELECT * FROM people WHERE id = 1 FOR UPDATE; -- 锁定id为1的这一行 ,COMMIT;
session2
SET autocommit = 0; -- 取消自动提交
UPDATE people SET name = "xxx" WHERE id = 1; -- 此时阻塞,直到session1 提交才会暂停阻塞
COMMIT; -- 提交

上一篇 下一篇

猜你喜欢

热点阅读