mysql 高级第三天:
回顾:
- 7 种join 的链接写法!
扩展掌门人的练习!
总结:写多表关联的步骤!
2. 索引的类型:
单一索引:
主键索引:
符合索引:
唯一索引:
3. explain + sql
id: 判断表的读取顺序!
type:
system>const>eq_ref>ref>range>index>ALL
key_len:
使用到索引的长度,通常这个值越大越好!
公式:
rows:列显示MySQL认为它执行查询时必须检查的行数。值越小越好
Extra;
Using filesort: 如果额外的列中出现了这个标识 , 则表示排序没有使用到索引!
解决方案:给排序字段添加索引
create index idx_name on tableName();
Using temporary: 表示分组没有使用到索引!
Using index:表示使用了覆盖索引 :覆盖索引【后面的检索条件,正好在查询项中也存在!】
using join buffer :表示关联字段没有使用索引!
4. 函数,存储过程! 最好能记住!
java : 有返回值的方法!
函数定义:CREATE [OR REPLACE] FUNCTION <过程名>[(参数列表)] RETURN 数据类型 IS
[局部变量声明]
BEGIN
可执行语句 【普通的sql】
EXCEPTION
异常处理语句
END [<过程名>];
java :没用返回值的方法!
存储过程定义:CREATE [OR REPLACE] PROCEDURE <过程名>[(参数列表)] IS
[局部变量声明]
BEGIN
可执行语句
EXCEPTION
异常处理语句
END [<过程名>];
重点:
- 删除索引的存储过程!{了解}
emp: 50万
dept: 1万
删除:drop index idx_name on tname;
#
功能: public void del(String table_schema ,String table_name){
List<String> sList = SELECT index_name FROM information_schema.STATISTICS WHERE table_name=table_name AND table_schema=table_schema;
for(int i=0;i<sList.size();i++){
DROP INDEX sList.get(i) ON emp;
}
}
2. 索引使用:必须记住!
a. 全值匹配我最爱
CREATE INDEX idx_age_deptid_name ON emp(age,deptid,NAME);
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid=4 AND emp.name = 'abcd';
b. 最佳左前缀法则
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 AND emp.name = 'abcd'; # 跳过了deptId 导致后面的name 不能使用索引!
或者
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.deptid=1 AND emp.name = 'abcd'; # 直接跳过了age ,后面的都不能使用索引!
# 创建的索引列都存在! mysql 的优化器会自动给你排序!
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE deptid=4 AND emp.age=30 AND emp.name = 'abcd';
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE deptid=4 AND emp.name = 'abcd' AND emp.age=30;
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.name = 'abcd' AND deptid=4 AND emp.age=30;
c. 计算、函数导致索引失效
d. 范围条件右边的列索引失效
SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 AND emp.deptId>20 AND emp.name = 'abc' ;
SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 AND emp.name = 'abc' AND emp.deptId>20 ;
如果有范围条件查询的话,那么我们将其放在后面:建立对应的复合索引即可!
e. 不等于(!= 或者<>)索引失效
f. is not null无法使用索引,is null可使用索引
g. like以通配符%开头索引失效
h. 类型转换导致索引失效
3. 关联查询优化
left Join
EXPLAIN SELECT SQL_NO_CACHE * FROM class LEFT JOIN book ON class.card = book.card;
优化应该在on 条件后面!
情况一:在class 上添加索引
create index idx_card on class(card);
情况二:在book 上添加索引
create index idx_card on book(card);
综上所述:
建立索引的时候,应该在从表{被驱动表}上建立!
inner Join
EXPLAIN SELECT SQL_NO_CACHE * FROM class INNER JOIN book ON class.card=book.card;
会自动选择驱动表!
mysql 没有full join !
4. 子查询优化:
优化方案:
看where 筛选条件
关联条件 on
所有的条件:
id : 主键索引
ceo : dept.ceo 对应的掌门人
deptid = 部门Id 忽略!
优化方案: 优化ceo!
子查询:
explain SELECT a.name ,(SELECT c.name FROM t_emp c WHERE c.id=b.ceo) AS ceoname FROM t_emp a LEFT JOIN t_dept b ON a.deptid = b.id ;
left Join
explain SELECT a.name,c.name AS ceoname FROM t_emp a LEFT JOIN t_dept b ON a.deptid = b.id LEFT JOIN t_emp c ON b.ceo = c.id ;
临时表:
explain SELECT ab.name,c.name AS ceoname FROM ( SELECT a.name,b.ceo FROM t_emp a LEFT JOIN t_dept b ON a.deptid = b.id ) ab LEFT JOIN t_emp c ON ab.ceo = c.id ;
能使用left join 就不要使用子查询!
能够使用not in 的 就尽量替换成 LEFT JOIN xxx ON xx WHERE xx IS NULL
NOT IN -->LEFT JOIN xxx ON xx WHERE xx IS NULL
排序、分组优化
order by ``` a. 无过滤 不索引!b. 顺序错,必排序!
c. 方向反 必排序
当在查询数据的时候,如果将排序的字段用上了索引,那么效率必然会高!
总结:
where
on
order by
索引的选择:
当【范围条件】和【group by 或者 order by】的字段出现二选一时,优先观察条件字段的过滤数量,
如果过滤的数据足够多,而需要排序的数据并不多时,优先把索引放在范围字段上。反之,亦然。
双路排序和单路排序 了解:
双路排序:两次io
单路排序:一次io 但是需要调整sort_buffer_size 的容量,避免发生多次io!
提高order by 的排序速度:
增大sort_buffer_size参数的设置 1M-8M
增大max_length_for_sort_data参数的设置 1024-8192字节
减少select 后面的查询的字段。 禁止使用select *
修改配置文件!
<br />GROUP BY关键字优化<br />
group by 先排序再分组,遵照索引建的最佳左前缀法则<br />
当无法使用索引列,增大max_length_for_sort_data和sort_buffer_size参数的设置<br />
where高于having,能写在where限定的条件就不要写在having中了<br />
group by没有过滤条件,也可以用上索引。Order By 必须有过滤条件才能使用上索引。
2.
覆盖索引:<br />
使用explain + sql ,在额外的选项中出现了 Using index ,则就是使用到了覆盖索引!
select * from emp where id = 1; 表示只查询一次就可以找到数据! select id,name from emp where name = ‘zhangsan’; name 不是索引! 表示查询两次! 上述这个过程叫回表! 【了解】
引出覆盖索引! select sql_no_cache id,age,deptid from emp where name like ‘%abc’; # 只需要查询一次!
结论: 查询的时候 尽量 使用覆盖索引!{查询字段,尽量是索引字段}
3.
慢查询日志 {了解}<br />
a. sql 语句执行的过程中超出了预定时间!<br />
b. 修改my.cnf<br />
slow_query_log =1<br />
slow_query_log_file=/var/lib/mysql/localhost-slow.log <br />
long_query_time=3<br />
log_output=FILE
c. 直接使用mysqldumpslow 进行分析: mysqldumpslow -s r -t 10 /var/lib/mysql/localhost-slow.log
总结:<br />
上午<br />
a. 针对是where 条件后面的索引优化!哪些能用索引,哪些不能用索引!
b. 关联查询优化
on 条件 ,在被驱动表上建立索引!
c. 能用left join 就不使用子查询!
d. order by group by
下午:
1. 排序、分组优化
a. 无过滤 不索引!
b. 顺序错,必排序!
c. 方向反 必排序
2. 覆盖索引 如何使用!
尽量把查询项,与帅选项做成索引!
select id,name,sex,age,addr,stuNo,email,createTimne,updateTime from stu where name = 'zs';
3. 慢查询 - 了解!
```