0
点赞
收藏
分享

微信扫一扫

Mysql优化(4)查询优化

二、查询优化
5、优化查询语句
1、用JOIN替代子查询(不创建tmp table)
2、子查询(创建tmp table),避免表锁死
3、不要多余的字段
4、相同类型来比较
5、在使用索引的字段上,尽量不用函数
6、尽量不要用LIKE和通配符,能用代码解决的,尽量不用联表查询
6、使用UNION 来代替手动创建的临时表
7、事务的使用
1、尽量不要使用事务
2、事务会锁库,尽量用锁表的方式做事务

1、索引与查询
1:索引类型
1.1 B-tree索引
注: 名叫btree索引,大的方面看,都用的平衡树,但具体的实现上, 各引擎稍有不同,
比如,严格的说,NDB引擎,使用的是T-tree
Myisam,innodb中,默认用B-tree索引
但抽象一下---B-tree系统,可理解为”排好序的快速查找结构”.
1.2 hash索引
在memory表里,默认是hash索引, hash的理论查询时间复杂度为O(1)

疑问: 既然hash的查找如此高效,为什么不都用hash索引?
答:
1:hash函数计算后的结果,是随机的,如果是在磁盘上放置数据,
比主键为id为例, 那么随着id的增长, id对应的行,在磁盘上随机放置.
2: 不法对范围查询进行优化.
3: 无法利用前缀索引. 比如 在btree中, field列的值“hellopworld”,并加索引
查询 xx=helloword,自然可以利用索引, xx=hello,也可以利用索引. (左前缀索引)
因为hash(‘helloword’),和hash(‘hello’),两者的关系仍为随机
4: 排序也无法优化.
5: 必须回行.就是说 通过索引拿到数据位置,必须回到表中取数据
以 index(a,b,c) 为例,
语句 索引是否发挥作用
Where a=3 是,只使用了a列
Where a=3 and b=5 是,使用了a,b列
Where a=3 and b=5 and c=4 是,使用了abc
Where b=3  /  where c=4 否
Where a=3 and c=4 a列能发挥索引,c不能
Where a=3 and b>10 and c=7 A能利用,b能利用, C不能利用
同上,where a=3 and b like ‘xxxx%’ and c=7 A能用,B能用,C不能用

假设某个表有一个联合索引(c1,c2,c3,c4)一下——只能使用该联合索引的c1,c2,c3部分
A where c1=x and c2=x and c4>x and c3=x 4
B where c1=x and c2=x and c4=x order by c3 2
C where c1=x and c4= x group by c3,c2 1
D where c1=x and c5=x order by c2,c3 1
E where c1=x and c2=x and c5=? order by c2,c3 2

innodb的主索引文件上 直接存放该行数据, 称为聚簇索引,次索引指向对主键的引用
myisam中, 主索引和次索引,都指向物理行(磁盘位置).

注意: innodb来说,
1: 主键索引 既存储索引值, 又在叶子中存储行的数据
2: 如果没有主键, 则会Unique key做主键
3: 如果没有unique,则系统生成一个内部的rowid做主键.
4: 像innodb中,主键的索引结构中,既存储了主键值,又存储了行数据,这种结构称为”聚簇索引”
优势: 根据主键查询条目比较少时,不用回行(数据就在主键节点下)
劣势: 如果碰到不规则数据插入时,造成频繁的页分裂.

索引覆盖:
索引覆盖是指 如果查询的列恰好是索引的一部分,那么查询只需要在索引文件上进行,不需要回行到磁盘再找数据.
这种查询速度非常快,称为”索引覆盖”

in子查询陷阱
EXPLAIN select from test where a1 in (select a1 from test where b2 = 1);
EXPLAIN select
from test where a1 in (97806,64883,12806,78011,88286,82805,9857,27983,18094,24172);
EXPLAIN select a1 from test inner JOIN (select a1 from test2 where to= 4656) as t2 using (a1);

from 型子查询:
注意::内层from语句查到的临时表, 是没有索引的.
所以: from的返回内容要尽量少.

我们查min(id), id是主键,查Min(id)非常快.
select min(id) from it_area where pid=69;
select id from it_area use index(primary) where pid=69 limit 1;

4: union优化
注意: union all 不过滤 效率提高,如非必须,请用union all
因为 union去重的代价非常高, 放在程序里去重.

count() 优化
误区:
1:myisam的count()非常快
答: 是比较快,.但仅限于查询表的”所有行”比较快, 因为Myisam对行数进行了存储.
一旦有条件的查询, 速度就不再快了.尤其是where条件的列上没有索引.

2: 假如,id<100的商家都是我们内部测试的,我们想查查真实的商家有多少?
select count() from lx_com where id>=100; (1000多万行用了6.X秒)
小技巧:
select count(
) from lx_com; 快
select count() from lx_com where id<100; 快
select count(
) frol lx_com -select count() from lx_com where id<100; 快
select (select count(
) from lx_com) - (select count(*) from lx_com where id<100)

3: group by
注意:
1:分组用于统计,而不用于筛选数据.
比如: 统计平均分,最高分,适合, 但用于筛选重复数据,则不适合.
以及用索引来避免临时表和文件排序

2: 以A,B表连接为例 ,主要查询A表的列,
那么 group by ,order by 的列尽量相同,而且列应该显示声明为A的列

imit offset,N, 当offset非常大时, 效率极低,
原因是mysql并不是跳过offset行,然后单取N行,
而是取offset+N行,返回放弃前offset行,返回N行.
效率较低,当offset越大时,效率越低

优化办法:
1: 从业务上去解决
办法: 不允许翻过100页
以百度为例,一般翻页到70页左右.

1:不用offset, 用条件查询.

3: 非要物理删除,还要用offset精确查询,还不限制用户分页,怎么办?
分析: 优化思路是 不查,少查,查索引,少取.
我们现在必须要查,则只查索引,不查数据,得到id.
再用id去查具体条目. 这种技巧就是延迟索引.延迟关联
mysql> select id,name from lx_com inner join (select id from lx_com limit 5000000,10) as tmp using(id);

举报

相关推荐

0 条评论