[英]Help me optimize this MySql query
我有一个MySql查询,需要很长时间才能运行(大约7秒)。 问题似乎出在查询的此部分中的OR:“((tblprivateitem.userid =?userid OR tblprivateitem.userid = 1)”。 如果跳过“ OR tblprivateitem.userid = 1”部分,则只需0.01秒。 由于需要这一部分,因此我需要找到一种优化此查询的方法。 有任何想法吗?
查询:
SELECT
tbladdeditem.addeditemid,
tblprivateitem.iitemid,
tblprivateitem.itemid
FROM tbladdeditem
INNER JOIN tblprivateitem
ON tblprivateitem.itemid=tbladdeditem.itemid
AND (tblprivateitem.userid=?userid OR tblprivateitem.userid=1)
WHERE tbladdeditem.userid=?userid
说明:
id select_type table type possible_keys key key_len ref rows extra
1 SIMPLE tbladdeditem ref userid userid 4 const 293 Using where
1 SIMPLE tblprivateitem ref userid,itemid itemid 4 tbladdeditem.itemid 2 Using where
表:
tbladdeditem包含1100万行:
CREATE TABLE `tbladdeditem` (
`addeditemid` int(11) NOT NULL auto_increment,
`itemid` int(11) default NULL,
`userid` mediumint(9) default NULL,
PRIMARY KEY (`addeditemid`),
KEY `userid` (`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
tblprivateitem包含2700 000行:
CREATE TABLE `tblprivateitem` (
`privateitemid` int(11) NOT NULL auto_increment,
`userid` mediumint(9) default '1',
`itemid` int(10) NOT NULL,
`iitemid` mediumint(9) default NULL,
PRIMARY KEY (`privateitemid`),
KEY `userid` (`userid`),
KEY `itemid` (`itemid`) //Changed this index to only use itemid instead
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
我会尝试这样做,在您原始的JOIN
您有一个与参数关联的OR
,将其移至WHERE
子句。
SELECT
tbladdeditem.addeditemid,
tblprivateitem.iitemid,
tblprivateitem.itemid
FROM tbladdeditem
INNER JOIN tblprivateitem
ON tblprivateitem.itemid=tbladdeditem.itemid
WHERE tbladdeditem.userid=?userid
AND (tblprivateitem.userid=?userid OR tblprivateitem.userid=1)
由于您在where子句中有谓词条件tbladdeditem.userid=?userid
,因此我不认为您在tbladdeditem.userid=?userid
条件中需要它。请尝试从tbladdeditem.userid=?userid
条件tbladdeditem.userid=?userid
其删除,(如果您使用Or来处理where参数为null,如果不将其保留为Or,则使用Coalesce
代替OR
)
-- If Or is to provide default for when (?userid is null...
SELECT a.addeditemid, p.iitemid, p.itemid
FROM tbladdeditem a
JOIN tblprivateitem p
ON p.itemid=a.itemid
WHERE a.userid=?userid
AND p.userid=Coalesce(?userid, 1)
-- if not then
SELECT a.addeditemid, p.iitemid, p.itemid
FROM tbladdeditem a
JOIN tblprivateitem p
ON p.itemid=a.itemid
WHERE a.userid=?userid
AND (p.userid=?userid Or p.userid = 1)
其次,如果在这两个表的userId列上没有索引,请考虑添加一个。
最后,如果所有这些均失败,请尝试转换为两个单独的查询并将它们合并在一起:
Select a.addeditemid, p.iitemid, p.itemid
From tbladdeditem a
Join tblprivateitem p
On p.itemid=a.itemid
And p.userId = a.Userid
Where p.userid=?userid
Union
Select a.addeditemid, p.iitemid, p.itemid
From tbladdeditem a
Join tblprivateitem p
On p.itemid=a.itemid
And p.userId = a.Userid
Where p.userid = 1
UPDATE
我让我的查询和模式完全匹配您的原始问题,多列键以及所有其他内容。 唯一可能的区别是,我在每个表中填充了200万个条目。 我的查询(您的查询)在0.15秒内运行。
delimiter $$
set @userid = 6
$$
SELECT
tbladdeditem.addeditemid, tblprivateitem.iitemid, tblprivateitem.itemid
FROM tbladdeditem
INNER JOIN tblprivateitem
ON tblprivateitem.itemid=tbladdeditem.itemid
AND (tblprivateitem.userid=@userid or tblprivateitem.userid = 1)
WHERE tbladdeditem.userid=@userid
我的解释与您所做的相同,根据我的数据,我的查询返回了1000多个匹配项,而没有任何问题。 完全不知所措,因为您实际上不应该遇到这些问题-运行的MySQL版本非常有限吗? 您正在运行64位吗? 有足够的记忆力吗?
我已经假设您的查询效果不佳,而当我的查询成功时,我已经解决了您的问题。 所以现在我吃乌鸦了。 我会发布一些我走的路。 但我告诉您,您查询的发布方式本来就很好。 我只能想象您的MySQL撞击硬盘或其他东西。 对不起,我无法提供更多帮助。
上一个响应(这也是更新)
我崩溃了,并在自己的数据库中重新创建了您的问题。 在尝试对userid
和itemid
独立索引后,我无法在几秒钟内得到查询,因此我按照查询的指示设置了非常具体的多列键。 请注意,在tbladdeditem
,多列查询以itemid
开头,而在tblprivateitem
,列则相反:
这是我使用的架构:
CREATE TABLE `tbladdeditem` (
`addeditemid` int(11) NOT NULL AUTO_INCREMENT,
`itemid` int(11) NOT NULL,
`userid` mediumint(9) NOT NULL,
PRIMARY KEY (`addeditemid`),
KEY `userid` (`userid`),
KEY `i_and_u` (`itemid`,`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `tblprivateitem` (
`privateitemid` int(11) NOT NULL AUTO_INCREMENT,
`userid` mediumint(9) NOT NULL DEFAULT '1',
`itemid` int(10) NOT NULL,
`iitemid` mediumint(9) NOT NULL,
PRIMARY KEY (`privateitemid`),
KEY `userid` (`userid`),
KEY `itemid` (`itemid`),
KEY `u_and_i` (`userid`,`itemid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
我在每个表中填充了200万个随机数据条目。 我做了一些假设:
这使每个用户在每个表中都有大约一千个条目。
这是查询的两个版本(我在编辑器中使用工作台):
版本1-对联接执行所有过滤。
结果:0.016秒返回1297行
delimiter $$
set @userid = 3
$$
SELECT
a.addeditemid,
p.iitemid,
p.itemid
FROM tblprivateitem as p
INNER JOIN tbladdeditem as a
ON (p.userid in (1, @userid))
AND p.itemid = a.itemid
AND a.userid = @userid
$$
这是解释:
EXPLAIN:
id select_type table type key ref rows extra
1 SIMPLE p range u_and_i 2150 Using where; Using index
1 SIMPLE a ref i_and_u 1 Using where; Using index
版本2-预先过滤
结果:0.015秒返回1297行
delimiter $$
set @userid = 3
$$
SELECT
a.addeditemid,
p.iitemid,
p.itemid
from
(select userid, itemid, iitemid from tblprivateitem
where userid in (1, @userid)) as p
join tbladdeditem as a on p.userid = a.userid and a.itemid = p.itemid;
where a.userid = @userid
$$
这是解释:
id select_type table type key ref rows extra
1 PRIMARY <derived2> ALL null null 2152
1 PRIMARY a ref i_and_u p.itemid,const 1 Using where; Using index
2 DERIVED p1 range u_and_i 2150 Using where
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.