赞
踩
学习视频:尚硅谷MySQL数据库高级,mysql优化,数据库优化_哔哩哔哩_bilibili
文档是复制尚硅谷的复习资料,个人只是为了方便复习。
目录
12.7 select tables optimized away
Management Serveices & Utilities
|
系统管理和控制工具
|
---|---|
SQL Interface:
|
SQL
接口。接受用户的
SQL
命令,并且返回用户需要查询的结果。比如
select from
就是调用
SQL Interface
|
Parser
|
解析器。
SQL
命令传递到解析器的时候会被解析器验证和解析
|
Optimizer
|
查询优化器。
SQL
语句在查询之前会使用查询优化器对查询进行优化,比如有
where
条件时,优化器来决定先投影还是先过滤。
|
Cache
和
Buffer
|
查询缓存。如果查询缓存有命中的查询结果,查询语句就可以直接去查询缓存中取数据。这个缓存机制是由一系列小缓存组成的。比如表缓存,记录缓存,key
缓存,
权限缓存等
|
根据 Query_ID,可以进一步执行 show profile cpu,block io for query Query_id 来查看 sql 的具体执行步骤。
对比项
| MyISAM | InnoDB |
外键
|
不支持
|
支持
|
事务
|
不支持
|
支持
|
行表锁
|
表锁,即使操作一条记录也会锁住整个表, 不适合高并发的操作
|
行锁,
操作时只锁某一行,不对其它行有影响,
适合高并发
的操作
|
缓存
|
只缓存索引,不缓存真实数据
|
不仅缓存索引还要缓存真实数据,对内存要求较高,而且内存大小对性能有决定性的影响
|
关注点
|
读性能
|
并发写、事务、资源
|
默认安装
|
Y
|
Y
|
默认使用
|
N
|
Y
|
自 带 系 统 表
使用
|
Y
|
N
|
show engines:查看所有的数据库引擎
CREATE TABLE `t_dept` (`id` INT(11) NOT NULL AUTO_INCREMENT,`deptName` VARCHAR(30) DEFAULT NULL,`address` VARCHAR(40) DEFAULT NULL,PRIMARY KEY (`id`)) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `t_emp` (`id` INT(11) NOT NULL AUTO_INCREMENT,`name` VARCHAR(20) DEFAULT NULL,`age` INT(3) DEFAULT NULL,`deptId` INT(11) DEFAULT NULL,empno int not null,PRIMARY KEY (`id`),KEY `idx_dept_id` (`deptId`)#CONSTRAINT `fk_dept_id` FOREIGN KEY (`deptId`) REFERENCES `t_dept` (`id`)) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO t_dept(deptName,address) VALUES(' 华山 ',' 华山 ');INSERT INTO t_dept(deptName,address) VALUES(' 丐帮 ',' 洛阳 ');INSERT INTO t_dept(deptName,address) VALUES(' 峨眉 ',' 峨眉山 ');INSERT INTO t_dept(deptName,address) VALUES(' 武当 ',' 武当山 ');INSERT INTO t_dept(deptName,address) VALUES(' 明教 ',' 光明顶 ');INSERT INTO t_dept(deptName,address) VALUES(' 少林 ',' 少林寺 ');INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 风清扬 ',90,1,100001);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 岳不群 ',50,1,100002);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 令狐冲 ',24,1,100003);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 洪七公 ',70,2,100004);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 乔峰 ',35,2,100005);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 灭绝师太 ',70,3,100006);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 周芷若 ',20,3,100007);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 张三丰 ',100,4,100008);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 张无忌 ',25,5,100009);INSERT INTO t_emp(NAME,age,deptId,empno) VALUES(' 韦小宝 ',18,null,100010);
select * from t_emp a inner join t_dept b on a.deptId = b.id
2. 列出所有人员及其部门信息
select * from t_emp a left join t_dept b on a.deptId = b.id
3. 列出所有部门的人员信息
select * from t_emp a right join t_dept b on a.deptId = b.id
4. 列出没有部门的人员信息
select * from t_emp a left join t_dept b on a.deptId = b.id where b.id is null
5. 列出没有人员的部门信息
select * from t_emp a right join t_dept b on a.deptId = b.id where a.id is null
6. 所有人员和部门的对应关系
select * from t_emp a left join t_dept b on a.deptId = b.id
union
select * from t_emp a right join t_dept b on a.deptId = b.id
7. 所有没有入部门的人员和没人入的部门
select * from t_emp a left join t_dept b on a.deptId = b.id where b.id is null
union
select * from t_emp a right join t_dept b on a.deptId = b.id where a.id is null
所表一起创建:CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name VARCHAR(200),PRIMARY KEY(id),KEY (customer_name));
单独建单值索引:CREATE INDEX idx_customer_name ON customer(customer_name);
概念:索引列的值必须唯一,但允许有空值
随表一起创建:CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name VARCHAR(200),PRIMARY KEY(id),KEY (customer_name),UNIQUE (customer_no));
单独建唯一索引:CREATE UNIQUE INDEX id x_customer_no ON customer(customer_no);
概念:设定为主键后数据库会自动建立索引,innodb为聚簇索引
随表一起建索引CREATE TABLE customer (id INT(10) UNSIGNEDAUTO_INCREMENT ,customer_no VARCHAR(200),customer_nameVARCHAR(200),PRIMARY KEY(id));
单独建主键索引:ALTER TABLE customer add PRIMARY KEY customer(customer_no);
删除 建主键索引:ALTER TABLE customer drop PRIMARY KEY ;
修改 建主键索引:必须先删除掉 (drop) 原索引,再新建 (add) 索引
概念:即一个索引包含多个列
随表一起建索引:CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name VARCHAR(200),PRIMARY KEY(id),KEY (customer_name),UNIQUE (customer_name),KEY (customer_no,customer_name));
单独建索引:CREATE INDEX idx_no_name ON customer(customer_no,customer_name);
操作
|
命令
|
---|---|
创建
|
CREATE [UNIQUE ] INDEX [indexName] ON table_name(column))
|
删除
|
DROP INDEX [indexName] ON mytable;
|
查看
|
SHOW INDEX FROM table_name\G
|
使 用
Alter
命令
|
ALTER TABLE tbl_name ADD PRIMARY KEY (column_list)
:
该语句添加一个主键,
这意味着索引值必须是唯一
,且不能为
NULL
。
|
ALTER TABLE tbl_name ADD PRIMARY KEY (column_list)这条语句创建索引的值
必须要是唯一的
(除NULL外,NULL可能会出现多次)
| |
ALTER TABLE tbl_name ADD INDEX index_name (column_list):
添加普通索引,
索引值可出现多次。
| |
ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list):
该语句指定了索引为
FULLTEXT
,
用于全文索
引。
|
1、Mysql中专门负责优化SELECT语句的优化器模块,主要功能:通过计算分析系统中收集到的统计信息,为客户端请求的Query提供他认为最优的执行计划(他认为最优的数据检索方式,但不见得DBA认为是最优的,这部分最耗费时间)
2、当客户端向MySQL请求一条Query,命令解析器模块完成请求分类,区别出示SELECT并转发给MySQL Query Optimizer时,MySQL Query Optimizer首先会对整条Query进行优化,处理掉一些常量表达式的预算,直接换算成常量值。并对Query中查询条件进行简化和转换,如去掉一些无用或显而易见的条件、结构调整没有Himt或Hint信息(如果有),则会读取所涉及对象的统计信息,根据Query进行写相应的计算分析,然后再得出最后的执行计划。
能干嘛
CREATE TABLE t1(id INT(10) AUTO_INCREMENT,content VARCHAR(100) NULL , PRIMARY KEY (id));CREATE TABLE t2(id INT(10) AUTO_INCREMENT,content VARCHAR(100) NULL , PRIMARY KEY (id));CREATE TABLE t3(id INT(10) AUTO_INCREMENT,content VARCHAR(100) NULL , PRIMARY KEY (id));CREATE TABLE t4(id INT(10) AUTO_INCREMENT,content VARCHAR(100) NULL , PRIMARY KEY (id));INSERT INTO t1(content) VALUES(CONCAT('t1_',FLOOR(1+RAND()*1000)));INSERT INTO t2(content) VALUES(CONCAT('t2_',FLOOR(1+RAND()*1000)));INSERT INTO t3(content) VALUES(CONCAT('t3_',FLOOR(1+RAND()*1000)));INSERT INTO t4(content) VALUES(CONCAT('t4_',FLOOR(1+RAND()*1000)));
explain select t2.*
from t1,t2,t3
where t1.id = t2.id and t1.id = t3.id
and t1.content = ''
explain select t2.*
from t2
where id = (select id
from t1
where id =(select t3.id
from t3
where t3.content = ''))
②id 不同, 如果是子查询,id 的序号会递增,id 值越大优先级越高,越先被执行
explain select t2.* from (
select t3.id
from t3
where t3.content = '') s1, t2
where s1.id = t2.id;
表示通过索引一次就找到了,const 用于比较 primary key 或者 unique 索引。因为只匹配一行数据,所以很快 如将主键置于 where 列表中,MySQL 就能将该查询转换为一个常量。
唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描。
建立索引后:
6.7 all
Full Table Scan,将遍历全表以找到匹配的行。
利用索引来关联子查询,不再全表扫描。
该联接类型类似于 index_subquery。 子查询中的唯一索引。
显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值。
rows 列显示 MySQL 认为它执行查询时必须检查的行数。越少越好!
优化后,不再出现 filesort 的情况:
查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度。
优化后:
使用了连接缓存。
在 Myisam 中:
CREATE TABLE `dept` (`id` INT(11) NOT NULL AUTO_INCREMENT,`deptName` VARCHAR(30) DEFAULT NULL,`address` VARCHAR(40) DEFAULT NULL,ceo INT NULL ,PRIMARY KEY (`id`)) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;CREATE TABLE `emp` (`id` INT(11) NOT NULL AUTO_INCREMENT,`empno` INT NOT NULL ,`name` VARCHAR(20) DEFAULT NULL,`age` INT(3) DEFAULT NULL,`deptId` INT(11) DEFAULT NULL,PRIMARY KEY (`id`)#CONSTRAINT `fk_dept_id` FOREIGN KEY (`deptId`) REFERENCES `t_dept` (`id`)) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
1.3.1 随机产生字符串
DELIMITER $$CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255)BEGINDECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';DECLARE return_str VARCHAR(255) DEFAULT '';DECLARE i INT DEFAULT 0;WHILE i < n DOSET return_str =CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1));SET i = i + 1;END WHILE;RETURN return_str;END $$
# 用于随机产生多少到多少的编号DELIMITER $$CREATE FUNCTION rand_num (from_num INT ,to_num INT) RETURNS INT(11)BEGINDECLARE i INT DEFAULT 0;SET i = FLOOR(from_num +RAND()*(to_num -from_num+1));RETURN i;END$$
1.4.1 创建往 emp 表中插入数据的存储过程
DELIMITER $$CREATE PROCEDURE insert_emp( START INT , max_num INT )BEGINDECLARE i INT DEFAULT 0;#set autocommit =0 把 autocommit 设置成 0SET autocommit = 0;REPEATSET i = i + 1;
1.4.2 创建往 dept 表中插入数据的存储过程
# 执行存储过程,往 dept 表添加随机数据DELIMITER $$CREATE PROCEDURE `insert_dept`( max_num INT )BEGINDECLARE i INT DEFAULT 0;SET autocommit = 0;REPEATSET i = i + 1;INSERT INTO dept ( deptname,address,ceo ) VALUES (rand_string(8),rand_string(10),rand_num(1,500000));UNTIL i = max_numEND REPEAT;COMMIT;END$$
# 执行存储过程,往 dept 表添加 1 万条数据DELIMITER ;CALL insert_dept(10000);
1.5.2 添加数据到员工表
# 执行存储过程,往 emp 表添加 50 万条数据DELIMITER ;CALL insert_emp(100000,500000);
1.6.1 删除索引的存储过程
DELIMITER $$CREATE PROCEDURE `proc_drop_index`(dbname VARCHAR(200),tablename VARCHAR(200))BEGINDECLARE done INT DEFAULT 0;DECLARE ct INT DEFAULT 0;DECLARE _index VARCHAR(200) DEFAULT '';DECLARE _cur CURSOR FORSELECTindex_nameFROM information_schema.STATISTICSWHEREtable_schema=dbname AND table_name=tablename AND seq_in_index=1 ANDindex_name <>'PRIMARY' ;DECLARE CONTINUE HANDLER FOR NOT FOUND set done=2 ;OPEN _cur;FETCH_cur INTO _index;WHILE _index<>'' DOSET @str = CONCAT("drop index ",_index," on ",tablename );PREPARE sql_str FROM @str ;EXECUTE sql_str;DEALLOCATE PREPARE sql_str;SET _index='';FETCH_cur INTO _index;END WHILE;CLOSE _cur;END$$
1.6.2 执行存储过程
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid=4EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid=4 AND emp.name = 'abcd
结论:全职匹配我最爱指的是,查询的字段按照顺序在索引中都可以匹配到!
不在索引列上做任何操作(计算、函数、(自动 or 手动)类型转换),会导致索引失效而转向全表扫描。
结论:等号左边无计算!
create index idx_name on emp(name);
|
explain select sql_no_cache * from emp where name='30000'; |
explain select sql_no_cache * from emp where name=30000; |
结论:等号右边无转换!
explain SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid=5 AND emp.name = 'abcd'; |
explain SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid<=5 AND emp.name = 'abcd'; |
建议:将可能做范围查询的字段的索引顺序放在最后
explain SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptId=4 and name='XamgXt';
|
explain SELECT SQL_NO_CACHE age,deptId,name FROM emp WHERE emp.age=30 and deptId=4 and name='XamgXt';
|
当字段允许为 Null 的条件下:
is not null 用不到索引,is null 可以用到索引。
前缀不能出现模糊匹配!
使用 union all 或者 union 来替代:
Where
语句
|
索引是否被使用
|
---|---|
where a = 3
|
Y,
使用到
a
|
where a = 3 and b = 5
|
Y,
使用到
a
,
b
|
where a = 3 and b = 5 and c = 4
|
Y,
使用到
a,b,c
|
where b = 3
或者
where b = 3 and c = 4
或者
where c = 4
|
N
|
where a = 3 and c = 5
|
使用到
a
, 但是
c
不可以,
b
中间断了
|
where a = 3 and b > 4 and c = 5
|
使用到 a
和
b
,
c
不能用在范围之后,
b
断了
|
where a is null and b is not null
|
is null
支持索引 但是
is not null
不支持
,
所
以
a
可以使用索引
,
但是
b
不可以使用
|
where a <> 3
|
不能使用索引
|
where abs(a) =3
|
不能使用 索引
|
where a = 3 and b like 'kk%' and c = 4
|
Y,
使用到
a,b,c
|
where a = 3 and b like '%kk' and c = 4
|
Y,
只用到
a
|
where a = 3 and b like '%kk%' and c = 4
|
Y,
只用到
a
|
where a = 3 and b like 'k%kk%' and c = 4
|
Y,
使用到
a,b,c
|
CREATE TABLE IF NOT EXISTS `class` (`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,`card` INT(10) UNSIGNED NOT NULL,PRIMARY KEY (`id`));CREATE TABLE IF NOT EXISTS `book` (`bookid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,`card` INT(10) UNSIGNED NOT NULL,PRIMARY KEY (`bookid`));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
②两个查询字段调换顺序,发现结果也是一样的!
③在 book 表中,删除 9 条记录
EXPLAIN SELECT ed.name ' 人物 ',c.name ' 掌门 ' FROM(SELECT e.name,d.ceo from t_emp e LEFT JOIN t_dept d on e.deptid=d.id) edLEFT JOIN t_emp c on ed.ceo= c.id;
EXPLAIN SELECT e.name ' 人物 ',tmp.name ' 掌门 'FROM t_emp e LEFT JOIN (SELECT d.id did,e.name FROM t_dept d LEFT JOIN t_emp e ON d.ceo=e.id)tmpON e.deptId=tmp.did;
EXPLAIN SELECT e1.name ' 人物 ',e2.name ' 掌门 'FROM t_emp e1LEFT JOIN t_dept d on e1.deptid = d.idLEFT JOIN t_emp e2 on d.ceo = e2.id ;
Explain SELECT e2.name ' 人物 ',(SELECT e1.name FROM t_emp e1 where e1.id= d.ceo) ' 掌门 'from t_emp e2 LEFT JOIN t_dept d on e2.deptid=d.id;
结论:能够直接多表关联的尽量直接关联,不用子查询!
取所有不为掌门人的员工,按年龄分组!
select age as '年龄', count(*) as '人数' from t_emp where id not in
(select ceo from t_dept where ceo is not null) group by age;
此时,再次查询:
结论: 在范围判断时,尽量不要使用 not in 和 not exists,使用 left join on xxx is null 代替。
using filesort 说明进行了手工排序!原因在于没有 where 作为过滤条件!
结论: 无过滤,不索引。where,limt 都相当于一种过滤条件,所以才能使用上索引!
②explain select * from emp where age=45 order by deptid,empno;
deptid 作为过滤条件的字段,无法使用索引,因此排序没法用上索引
如果排序的字段,顺序有差异,就需要将差异的部分,进行一次倒置顺序,因此还是需要手动排序的!
①首先,清除 emp 上面的所有索引,只保留主键索引!
drop index idx_age_deptid_name on emp;
select e1.name empname,e1.age empage,e2.name ceoname,e2.age ceoagefrom t_emp e1 inner join t_dept d on e1.deptid=d.idinner join t_emp e2 on d.ceo=e2.idwhere e1.age>e2.age;
更换为大表,进行分析:
explain select e1.name empname,e1.age empage,e2.name ceoname,e2.age ceoage from emp e1 inner join dept d one1.deptid=d.idinner join emp e2 on d.ceo=e2.idwhere e1.age>e2.age;
两次 inner join 的被驱动表都已经用上了索引。
select e1.name from t_emp e1inner join(select deptid,AVG(age) avgage from t_empgroup by deptid) tmpon e1.deptid=tmp.deptidwhere e1.age<tmp.avgage;
更换为大表:
explain select e1.name from emp e1inner join(select deptid,AVG(age) avgage from empgroup by deptid) tmpon e1.deptid=tmp.deptidwhere e1.age<tmp.avgage;
select d.deptName,count(*)from t_emp e inner join t_dept don e.deptid=d.idwhere e.age>40group by d.id,d.deptNamehaving count(*)>=2
大表优化:
explain select d.deptName,count(*)from emp e inner join dept don e.deptid=d.idwhere e.age>40group by d.id,d.deptNamehaving count(*)>=2
select d2.deptName from t_emp e inner join t_dept d2 on e.deptid=d2.idleft join t_dept d on e.id=d.ceowhere d.id is null and e.deptid is not nullgroup by d2.deptName,d2.idhaving count(*)>=2;
explain select d2.deptName from emp e inner join dept d2 on e.deptid=d2.idleft join dept d on e.id=d.ceowhere d.id is null and e.deptid is not nullgroup by d2.deptName,d2.idhaving count(*)>=2;
大表关联:
explain select e.name,case when d.id is null then ' 否 ' else ' 是 ' end ' 是否为掌门 ' from emp eleft join dept don e.id=d.ceo;
优化:在 d 表的 ceo 字段建立索引即可!
select d.deptName,if(avg(age)>40,' 老鸟 ',' 菜鸟 ') from t_emp e inner join t_dept don d.id=e.deptid group by d.deptName,d.id
切换大表:
explain select d.deptName,if(avg(age)>40,' 老鸟 ',' 菜鸟 ') from dept d inner join emp eon d.id=e.deptidgroup by d.deptName,d.id
select * from t_emp einner join(select deptid,max(age) maxagefrom t_empgroup by deptid) tmpon tmp.deptid=e.deptid and tmp.maxage=e.age;
大表优化:
explain select * from emp einner join(select deptid,max(age) maxagefrom empgroup by deptid) tmpon tmp.deptid=e.deptid and tmp.maxage=e.age;
SQL
语句
|
描述
|
备注
|
---|---|---|
SHOW VARIABLES LIKE '%slow_query_log%';
|
查看慢查询日志是否开启
|
默认情况下
slow_query_log
的值为
OFF
,
表示慢查询日志是禁用的
|
set global slow_query_log=1;
|
开启慢查询日志
| |
SHOW VARIABLES LIKE 'long_query_time%';
|
查看慢查询设定阈值
|
单位秒
|
set long_query_time=1
|
设定慢查询阈值
|
单位秒
|
[mysqld]slow_query_log=1slow_query_log_file=/var/lib/mysql/atguigu-slow.loglong_query_time=3log_output=FILE
(2) 查看mysqldumpslow的帮助信息
得到返回记录集最多的 10 个 SQLmysqldumpslow -s r -t 10 /var/lib/mysql/atguigu-slow.log得到访问次数最多的 10 个 SQLmysqldumpslow -s c -t 10 /var/lib/mysql/atguigu-slow.log得到按照时间排序的前 10 条里面含有左连接的查询语句mysqldumpslow -s t -t 10 -g "left join" /var/lib/mysql/atguigu-slow.log另外建议在使用这些命令时结合 | 和 more 使用 ,否则有可能出现爆屏情况mysqldumpslow -s r -t 10 /var/lib/mysql/atguigu-slow.log | more
1.1 是什么
主服务器唯一 ID
server-id=1启用二进制日志 JAVAEE 课程系列log-bin= 自己本地的路径 /data/mysqlbinlog-bin=D:/devSoft/MySQLServer5.5/data/mysqlbin设置不要复制的数据库binlog-ignore-db=mysql设置需要复制的数据库binlog-do-db= 需要复制的主数据库名字设置 logbin 格式binlog_format=STATEMENT (默认)
mysql 主从复制起始时,从机不继承主机数据
# 从机服务 idserver-id = 2# 注意 my.cnf 中有 server-id = 1# 设置中继日志relay-log=mysql-relay
(5) 因修改过配置文件,请主机+从机都重启后台 mysql 服务
# 创建用户,并授权GRANT REPLICATION SLAVE ON *.* TO ' 备份账号 '@' 从机器数据库 IP' IDENTIFIED BY '123456';
(8) 查询 master 的状态,并记录下 File 和 Position 的值
# 查询 master 的状态show master status;
执行完此步骤后不要再操作主服务器 MYSQL,防止主服务器状态值变化
# 查询 master 的状态CHANGE MASTER TO MASTER_HOST=' 主机 IP',MASTER_USER=' 创建用户名 ',MASTER_PASSWORD=' 创建的密码 ',MASTER_LOG_FILE='File 名字 ',MASTER_LOG_POS=Position 数字 ;
(10) 启动从服务器复制功能
start slave;show slave status\G;
下面两个参数都是 Yes,则说明主从配置成功!
Slave_IO_Running: YesSlave_SQL_Running: Yes
(11) 主机新建库、新建表、insert 记录,从机复制
stop slave;
数据库中间件,前身是阿里的 cobar
垂直拆分、水平拆分
垂直+水平拆分
3.多数据源整合
“拦截”:Mycat 的原理中最重要的一个动词是“拦截”,它拦截了用户发送过来的 SQL 语句,首先对 SQL 语句做了一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此 SQL 发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户。
这种方式把数据库的分布式从代码中解耦出来,程序员察觉不出来后台使用 mycat 还是 mysql。
schema.xml 定义逻辑库,表、分片节点等内容 rule.xml 定义分片规则
server.xml 定义用户以及系统相关变量,如端口等.
3.启动前先修改 schema.xml
- <?xml version="1.0"?>
- <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
- <mycat:schema xmlns:mycat="http://io.mycat/">
- <!--逻辑库 name 名称, checkSQLschema sqlMaxLimit 末尾是否要加 limit xxx-->
- <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"> </schema>
- <!--逻辑库 name 名称, dataHost 引用的哪个 dataHost database:对应 mysql 的 database-->
- <dataNode name="dn1" dataHost="localhost1" database="db1" />
- <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
- writeType="0" dbType="mysql" dbDriver="native" switchType="1"
- slaveThreshold="100">
- <heartbeat>select user()</heartbeat>
- <!-- can have multi write hosts -->
- <writeHost host="hostM1" url="localhost:3306" user="root"
- password="123456">
- </writeHost>
- </dataHost>
- </mycat:schema>
4. 再修改 server.xml
- <user name="root">
- <property name="password">654321</property>
- <property name="schemas">TESTDB</property>
- </user>
5. 启动程序
控制台启动 :去 mycat/bin 目录下 mycat console 后台启动 :去 mycat/bin 目录下 mycat start
6.启动时可能出现报错
域名解析失败
用 vim 修改 /etc/hosts 文件,在 127.0.0.1 后面增加你的机器名
修改后重新启动网络服务
7. 后台管理窗口登录
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。