ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

【数据库优化】记一次Mysql的优化经历

2020-06-06 13:51:52  阅读:258  来源: 互联网

标签:where 数据库 索引 score Mysql sc 优化 id crm


记一次Mysql的优化经历

1.建立一个课程表
create table Course(

c_id int PRIMARY KEY,

name varchar(10)

)
2.建立一个学生表
create table Student(

s_id int PRIMARY KEY,

name varchar(10)

)
3.建立一个课程学生表
CREATE table SC(

    sc_id int PRIMARY KEY,

    s_id int,

    c_id int,

    score int

)
4.通过存储过程 插入七十万的数据
DELIMITER $$
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 course(c_id ,name) VALUES ((START+i),CONCAT("语文"));
UNTIL i = max_num
END REPEAT;
COMMIT;
END $$
DELIMITER $$
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 student(id ,name) VALUES (START+i,(CONCAT("小明",i)));
UNTIL i = max_num
END REPEAT;
COMMIT;
END $$
5.查询语文成绩为89的学生信息
select * from student s where s.s_id in (SELECT sc.s_id from sc sc where sc.score = 89 and sc.c_id = 1)

​ 执行后发现时间要的很久,我直接停止查询了

然后我们建立索引,提高查询速度

drop index  idx_sc_score on sc;
drop index  idx_sc_c_id on sc;

CREATE INDEX  idx_sc_score ON sc(score);
CREATE INDEX  idx_sc_c_id ON sc(c_id);

查询发现还是很慢,查看一下查询计划

存在全表扫描,速度太慢了

查看一下mysql的处理执行器优化过后的sql

在explain extended 后执行show warning

EXPLAIN EXTENDED select * from student s where s.s_id in (SELECT sc.s_id from sc sc where sc.score = 89 and sc.c_id = 1);
show WARNINGS

可以看到优化后的sql

SELECT
	`crm`.`s`.`s_id` AS `s_id`,
	`crm`.`s`.`name` AS `name`
FROM
	`crm`.`student` `s`
WHERE
	< in_optimizer > (
		`crm`.`s`.`s_id` ,< EXISTS > (
			SELECT
				1
			FROM
				`crm`.`sc`
			WHERE
				(
					(`crm`.`sc`.`c_id` = 1)
					AND (`crm`.`sc`.`score` = 89)
					AND (
						< CACHE > (`crm`.`s`.`s_id`) = `crm`.`sc`.`s_id`
					)
				)
		)
	)

可以看到mysql 经过优化后 将in修改为exists

SELECT count(1) from sc sc where sc.score = 89 and sc.c_id = 1
:1162

这个不符合exists后接大表的原则,需要循环700000*1162次

所以可以通过连表查询:

select * from student s INNER JOIN sc sc on s.s_id = sc.sc_id where sc.score = 89 and sc.c_id = 1

这样的话,速度快了很多 0.416s

查看执行计划:

还是有可以优化的空间

查看一下优化过后的sql

SELECT
	`crm`.`s`.`s_id` AS `s_id`,
	`crm`.`s`.`name` AS `name`,
	`crm`.`sc`.`sc_id` AS `sc_id`,
	`crm`.`sc`.`s_id` AS `s_id`,
	`crm`.`sc`.`c_id` AS `c_id`,
	`crm`.`sc`.`score` AS `score`
FROM
	`crm`.`student` `s`
JOIN `crm`.`sc`
WHERE
	(
		(
			`crm`.`s`.`s_id` = `crm`.`sc`.`sc_id`
		)
		AND (`crm`.`sc`.`c_id` = 1)
		AND (`crm`.`sc`.`score` = 89)
	)

先连表在去通过where条件过滤,还是很大,可以先将sc表中过滤后再去连表

select s.* from (SELECT sc.s_id from sc sc where sc.score = 89 and sc.c_id = 1) t INNER JOIN student s on s.s_id = t.s_id 

这样子以后,速度更快了0.121s

查看执行计划

![](....\image\数据库\explain 03.png)

这里用到了intersect 这样并集操作,就是两个索引同事检索,然后再求并集

在看score 和c_id这两个字段,区分度不高,我们可以建立联合索引,也可以提交高区分度

CREATE index ind_sc_score_id on sc(score,s_id)

删除之前的索引,然后执行后发现 0.056s快了一倍

这样还可以了

总结:

  1. 列类型尽量定义成数值类型,且长度尽可能短,如主键和外键,类型字段等等

  2. 建立单列索引

  3. 根据需要建立多列联合索引

当单个列过滤之后还有很多数据,那么索引的效率将会比较低,即列的区分度较低,

那么如果在多个列上建立索引,那么多个列的区分度就大多了,将会有显著的效率提高。

  1. 根据业务场景建立覆盖索引

只查询业务需要的字段,如果这些字段被索引覆盖,将极大的提高查询效率

  1. 多表连接的字段上需要建立索引

这样可以极大的提高表连接的效率

  1. where条件字段上需要建立索引

  2. 排序字段上需要建立索引

  3. 分组字段上需要建立索引

  4. Where条件上不要使用运算函数,以免索引失效

标签:where,数据库,索引,score,Mysql,sc,优化,id,crm
来源: https://www.cnblogs.com/simple-flw/p/13054445.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有