我遇到了某些查询性能问题,我有以下两个表:
CREATE TABLE `customers` (
`CustFullName` varchar(45) NOT NULL,
`CustPassword` varchar(45) NOT NULL,
`CustEmail` varchar(128) NOT NULL,
`SocialNetworkId` tinyint(4) NOT NULL,
`CustUID` varchar(64) CHARACTER SET ascii NOT NULL,
`CustMoney` bigint(20) NOT NULL DEFAULT '0',
`LastIpAddress` varchar(45) CHARACTER SET ascii NOT NULL,
`LastLoginTime` datetime NOT NULL DEFAULT '1900-10-10 10:10:10',
`SmallPicURL` varchar(120) CHARACTER SET ascii DEFAULT '',
`LargePicURL` varchar(120) CHARACTER SET ascii DEFAULT '',
`LuckyChips` int(10) unsigned NOT NULL DEFAULT '0',
`AccountCreationTime` datetime NOT NULL DEFAULT '2009-11-11 11:11:11',
`AccountStatus` tinyint(4) NOT NULL DEFAULT '1',
`CustLevel` int(11) NOT NULL DEFAULT '0',
`City` varchar(32) NOT NULL DEFAULT '',
`State` varchar(32) NOT NULL DEFAULT '0',
`Country` varchar(32) NOT NULL DEFAULT '',
`Zip` varchar(16) CHARACTER SET ascii NOT NULL,
`CustExp` bigint(20) NOT NULL DEFAULT '0',
PRIMARY KEY (`CustUID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
并且:
CREATE TABLE `mutualfriends` (
`CustUID` varchar(32) CHARACTER SET ascii NOT NULL,
`CustUID2` varchar(32) CHARACTER SET ascii NOT NULL,
`FType` tinyint(4) NOT NULL,
PRIMARY KEY (`CustUID`,`CustUID2`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
customers表包含1M行和mutalfriends约50k行。
我需要以下查询的结果:
SELECT c.CustUID, c.CustFullName, c.CustMoney, c.SmallPicURL
FROM `customers` c
WHERE c.`CustUID` = '9:2'
OR c.`CustUID` IN
(SELECT m.CustUID2 FROM mutualfriends m WHERE m.CustUID = '9:2');
OR c.`CustUID` IN
(SELECT m.CustUID FROM mutualfriends m WHERE m.CustUID2 = '9:2');
由于某些原因我不明白,这个查询大约需要10秒才能完成。 子查询每个包含不超过3行,如果我放置常量而不是:
(SELECT m.CustUID2 FROM mutualfriends m WHERE m.CustUID = '9:2');
并且:
(SELECT m.CustUID FROM mutualfriends m WHERE m.CustUID2 = '9:2');
例如:
SELECT c.CustUID, c.CustFullName, c.CustMoney, c.SmallPicURL
FROM `customers` c
WHERE c.`CustUID` = '9:2'
OR c.`CustUID` IN
('9:3','9:4','9:5');
OR c.`CustUID` IN
('9:6','9:7');
然后查询需要几毫秒才能完成。 我在这里做错了什么,这个查询不应该超过几毫秒......
我也可以添加这部分查询:
(SELECT m.CustUID2 FROM mutualfriends m WHERE m.CustUID = '9:2');
(SELECT m.CustUID FROM mutualfriends m WHERE m.CustUID2 = '9:2');
也需要几毫秒......
答案 0 :(得分:0)
网上有任意数量的网页可以告诉你如何优化查询,但我的第一个猜测是MySQL没有在共享朋友上使用索引,因为它是由两列组成的。
答案 1 :(得分:0)
看看http://dev.mysql.com/doc/refman/5.0/en/using-explain.html。此外,快速谷歌搜索将带来许多起点来处理SQL优化。大多数人依赖于EXPLAIN
,所以从那里开始。
关于您的查询,CustUID2
将触发全表扫描,因为它未直接编入索引。另外,要小心使用子查询,因为我遇到了一些优化器无法完全优化子查询的情况......在我的情况下,足以在更多查询中拆分查询(没有子查询) 。
它可能也有助于使用JOIN
,因为它们的处理方式与子查询不同。
答案 2 :(得分:0)
一些随机猜测:
(SELECT m.CustUID FROM mutualfriends m WHERE m.CustUID2 = '9:2');
... 可能无法有效使用索引(CustUID,CustUID2)。你必须检查解释计划。如果没有,请考虑添加另一个单一索引(CustUID2,CustUID)。
表达式
WHERE <constant>
OR <subquery>
...在Oracle中生成一个糟糕的计划。也许这也是MySQL的情况?它通常可以通过以某种方式处理子查询中的常量表达式或稍微改写逻辑来解决。
另一个想法是执行三个查询并将它们联合起来。如果您希望返回大量行,则此选项不太有吸引力,因为排序会破坏性能。
select *
from customer
where CustUID = '9:2'
union
select *
from customer
where CustUID in(select m.CustUID from mutualfriends m where m.CustUID2 = '9:2')
union
select *
from customer
where CustUID in(select m.CustUID2 from mutualfriends m where m.CustUID = '9:2')