我有一个MySql查询需要很长时间才能运行(大约7秒)。问题似乎与查询的这一部分中的OR有关:“(tblprivateitem.userid =?userid OR tblprivateitem.userid = 1)”。如果我跳过“OR tblprivateitem.userid = 1”部分,则只需0.01秒。由于我需要这部分,我需要找到一种优化此查询的方法。有什么想法吗?
QUERY:
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
TABLES:
tbladdeditem包含1 100 000行:
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包含2 700 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;
答案 0 :(得分:1)
我会尝试这样做,在您的原始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)
答案 1 :(得分:1)
由于你在where子句中有谓词条件tbladdeditem.userid=?userid
,我认为你不需要它在连接条件中。尝试从连接条件中删除它(如果你使用Or来处理如果参数为null,则使用Coalesce
而不是OR
),如果不将其保留为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
答案 2 :(得分:1)
<强>更新强>
我使我的查询和架构完全匹配您的原始问题,多列密钥和所有。唯一可能的区别是我在每个表中填入了两百万个条目。我的查询(您的查询)在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
我有相同的解释,你和我的数据,我的查询返回超过一千场比赛没有任何问题。完全不知所措,因为你真的不应该遇到这些问题 - 你是否有可能运行极限版本的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 - 预先过滤
结果:返回1297行的时间为0.015秒
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