Mysql 如何优化以下选择查询
我们有下表Mysql 如何优化以下选择查询,mysql,sql,mariadb,Mysql,Sql,Mariadb,我们有下表 id # primary key device_id_fk auth # there's an index on it old_auth # there's an index on it 和下面的查询 $select_user = $this->db->prepare(" SELECT device_id_fk FROM wtb_device_auths AS dv WHERE (dv.auth= :aut
id # primary key
device_id_fk
auth # there's an index on it
old_auth # there's an index on it
和下面的查询
$select_user = $this->db->prepare("
SELECT device_id_fk
FROM wtb_device_auths AS dv
WHERE (dv.auth= :auth OR dv.old_auth= :auth)
LIMIT 1
");
解释一下,我无法访问主客户机的服务器,但这里有另一个数据较少的客户机
由于auth上还有很多其他更新查询,因此更新查询开始写入较慢的查询日志,cpu峰值也随之增加
如果从auth中删除索引,则select查询将写入慢速查询日志,但不会写入更新。如果将索引添加到设备\u id\u fk
,则没有任何区别
我尝试使用union而不是or重写查询,但有人告诉我仍然存在cpu峰值,select查询仍然会写入慢速查询日志
$select_user = $this->db->prepare("
(SELECT device_id_fk
FROM wtb_device_auths
AS dv WHERE dv.auth= :auth)
UNION ALL
(SELECT device_id_fk
FROM wtb_device_auths AS dv
WHERE dv.old_auth= :auth)
LIMIT 1"
);
");
说明
通常,这是慢速查询日志中的唯一查询。有没有更理想的方式来编写查询?有没有更理想的方法来添加索引?客户端在运行LAMP的centos 6服务器上使用旧的MariaDB版本,相当于MYSQL 5.5
附加信息
每当向auth
添加索引时,记录到慢速查询日志的更新查询是
$update_device_auth = $this->db->prepare("UPDATE wtb_device_auths SET auth= :auth WHERE device_id_fk= :device_id_fk");
你的几个索引不应该减慢你的更新速度 您需要两个索引才能使更新和选择都能很好地执行。我最好的猜测是你从来没有同时拥有过这两个 您需要在
设备\u id\u fk
上建立索引,才能使此更新正常运行。不管它的索引是什么,它都应该声明为外键
您需要在auth,old\u auth
上有一个单独的组合索引,以便该查询能够很好地执行
假设没有太多的重复项,单独的auth
和old_auth
索引也应该可以正常工作。合并应该很快。。。除非有很多行匹配
如果还单独搜索old\u auth
,请在old\u auth
上添加索引
而且,正如其他人指出的那样,select
查询可以返回具有匹配身份或旧身份的多个匹配设备中的一个。这可能很糟糕。如果auth
和old_auth
用于识别设备
或者,您需要重新构造数据。持有相同值的多列是一个红色标志。正如您所经历的那样,它可能会导致索引激增,并限制您可以存储的版本数量。相反,每行只有一个身份验证,并允许每个设备有多行
create table wtb_device_auths (
id serial primary key,
device_id bigint not null references wtb_devices(id),
auth text not null,
created_at datetime not null default current_timestamp,
index(auth)
);
现在您只需要搜索一列
select device_id from wtb_device_auths where auth = ?
现在,一个设备可以有多个wtb_device_auths行。如果需要设备的当前身份验证,请搜索最新的身份验证
select device_id
from wtb_device_auths
where device_id = ?
order by created_at desc
limit 1
由于每个设备只有少量的身份验证,仅使用device\u id
索引可能会非常快;为一个设备对少数行进行排序会很快
如果没有,您可能需要一个额外的组合索引,如
created\u at,device\u id
。这包括单独按创建的进行搜索和排序,以及同时按创建的和设备id或
进行查询搜索和排序通常会导致缓慢的全表扫描。这个联合
技巧,加上适当的索引
要快得多:
( SELECT device_id_fk
FROM wtb_device_auths AS dv
WHERE dv.auth= :auth
LIMIT 1 )
UNION ALL
( SELECT device_id_fk
FROM wtb_device_auths AS dv
WHERE dv.old_auth= :auth
LIMIT 1 )
LIMIT 1
并有这些“综合”指数:
这些索引可以用相同的第一列替换现有索引
注意,我有3个限制
;你只有一个
UNION ALL涉及一个临时表。您应该升级到5.7(至少);该版本优化了临时表
没有排序依据的限制
给出一个随机行;可以吗
请为这个查询提供slowlog条目的完整文本——它包含可能有用的信息。如果“检查的行数”超过2行(或者可能是3行),则会出现一些奇怪的情况。评论不用于扩展讨论;这段对话已经结束。
select device_id
from wtb_device_auths
where device_id = ?
order by created_at desc
limit 1
( SELECT device_id_fk
FROM wtb_device_auths AS dv
WHERE dv.auth= :auth
LIMIT 1 )
UNION ALL
( SELECT device_id_fk
FROM wtb_device_auths AS dv
WHERE dv.old_auth= :auth
LIMIT 1 )
LIMIT 1
INDEX(auth, device_id)
INDEX(old_auth, device_id)