Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/79.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 如何优化以下选择查询_Mysql_Sql_Mariadb - Fatal编程技术网

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)