MySQL的优化案例都来自:
MySQL · 性能优化 · MySQL常见SQL错误用法
SELECT *
FROM operation
WHERE type = 'SQLStats'
AND name = 'SlowLog'
ORDER BY create_time
LIMIT 1000, 10;
DBA(data base administrator)会选择采用建立组合索引的形式来增加访问速度。
关于检索的理解,检索是以空间换取时间的一个策略。作用是在使用where语句进行过滤的时候可以加快查询进度,对于and这种组合过滤条件则需要创建组合索引。原理尚不清楚。
但是这里的limit如果后面第一个参数非常大,这样的查询会非常慢。把每一页的最大值比如#2017-03-16 14:00:00#当成查询条件就可以
SELECT *
FROM operation
WHERE type = 'SQLStats'
AND name = 'SlowLog'
AND create_time > '2017-03-16 14:00:00'
ORDER BY create_time limit 10;
mysql> explain extended SELECT *
> FROM my_balance b
> WHERE b.bpn = 14000000123
> AND b.isverified IS NULL ;
mysql> show warnings;
| Warning | 1739 | Cannot use ref access on index 'bpn' due to type or collation conversion on field 'bpn'
因为指定的bpn类型为字符串行,类型不匹配时,索引失效;查询速度可想而知。
UPDATE operation o
SET status = 'applying'
WHERE o.id IN (SELECT id
FROM (SELECT o.id,
o.status
FROM operation o
WHERE o.group = 123
AND o.status NOT IN ( 'done' )
ORDER BY o.parent,
o.id
LIMIT 1) t);
先执行子查询->父查询->祖父查询,按常理subquery是比类似的join 运算要慢的。所以,以上的语句可以写成…
update operation o
join (select o.id
,o.status
from operation o
where o.group = 123 and o.status not in ('done')
order by o.parent
,o.id
limit 1) t
on o.id = t.id
set status = 'applying'
日常的查询虽然用不到update但是这里我们还是要有意识多用join少用子查询。
SELECT *
FROM my_order o
INNER JOIN my_appraise a ON a.orderid = o.id
ORDER BY a.is_reply ASC,
a.appraise_time DESC
limit 0,20
;
如果字段is_reply
仅仅只有0,1两个值时,那么可以选择筛选+union的操作。
select *
from
((select *
from my_order o
join my_appraise a on a.orderid = o.id
where a.is_reply = 0
order by a.appraise_time desc
limit 0,20)
union
(select *
from my_order o
join my_appraise a on a.orderid = o.id
where a.is_reply = 1
order by a.appraise_time desc
limit 0,20))
order by a.is_reply asc
,appraise_time desc
limit 20
;
SELECT *
FROM my_neighbor n
LEFT JOIN my_neighbor_apply sra
ON n.id = sra.neighbor_id
AND sra.user_id = 'xxx'
WHERE n.topic_status < 4
AND EXISTS(SELECT 1
FROM message_info m
WHERE n.id = m.neighbor_id
AND m.inuser = 'xxx')
AND n.topic_type <> 5
原理类似case 3,勤用join少用subquery。而且,把inner join放在left join前面,可以节省时间。(但是如果inner join的数据量要大很多的话,除外。)
select *
from
my_neighbor n
left join
my_neighbor_apply sra
on
n.id = sra.neighbor_id
and sra.user_id = 'xxx'
inner join
message_info m
on
n.id = m.neighbor_id
and m.inuser = 'xxx'
where
n.topic_status<4
and n.topic_type <> 5
SELECT *
FROM (SELECT target,
Count(*)
FROM operation
GROUP BY target) t
WHERE target = 'rm-xxxx'
可以优化成
select
target
,count(*)
from
operation
where
target = 'rm-xxx'
group by
1
至少不符合条件的记录可以被筛选出去,不纳入计算了。
SELECT *
FROM my_order o
LEFT JOIN my_userinfo u
ON o.uid = u.uid
LEFT JOIN my_productinfo p
ON o.pid = p.pid
WHERE ( o.display = 0 )
AND ( o.ostaus = 1 )
ORDER BY o.selltime DESC
LIMIT 0, 15
** 明显 my_order 这张表是可以提前筛选的。**
select
*
from
(select
*
from
my_order o
where
o.display = 0
and o.status = 1
order by
o.selltime desc
limit
0,15) tmpo
left join
my_userinfo u
on
tmpo.uid = u.uid
left join
my_productinfo
on
tmpo.pid = p.pid
order by
o.selltime desc
limit
0,15
uid和pid分别是my_userinfo和my_productinfo的唯一主键。
SELECT a.*,
c.allocated
FROM (
SELECT resourceid
FROM my_distribute d
WHERE isdelete = 0
AND cusmanagercode = '1234567'
ORDER BY salecode limit 20) a
LEFT JOIN
(
SELECT resourcesid, sum(ifnull(allocation, 0) * 12345) allocated
FROM my_resources
GROUP BY resourcesid) c
ON a.resourceid = c.resourcesid
c表中我们只关心a中有的resourceid!!!! 这句话写得贼好。所以,改进措施…
with a as
(select
resourceid
from
my_distribute d
where
isdelete = 0
and cusmanagercode = '1234567'
order by
salecode
limit
20
)
select
a.*
,c.allocated
from
a
left join
(select
resourcesid
,sum(ifnull(allocation,0)*12345) allocated
from
my_resources
,a
where
a.resourcesid = my_resources.my_resources
group by
1) c
on
a.resourcesid = mr.resourcesid
group by
1