2010-10-01 82 views
0
我有一定的查詢性能問題

,我有以下2個表:查詢性能問題

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 

客戶表包含100萬行和大約50,000列mutalfriends。

我需要以下查詢的結果:

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 secconds完成。 子查詢中包含每次不超過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

網上有任何頁面會告訴你如何優化查詢,但我的第一個猜測是,MySQL沒有使用互助朋友的索引,因爲它由兩列組成。

+0

我不這麼認爲,因爲這行只需要幾個ms:(SELECT m.CustUID2 FROM mutualfriends m WHERE m.CustUID ='9:2'); – 2010-10-01 15:56:51

0

看一看http://dev.mysql.com/doc/refman/5.0/en/using-explain.html。另外一個快速的谷歌搜索將返回與大量的起點來處理SQL優化。雖然大多數依靠EXPLAIN,所以從那裏開始。

關於您的查詢,CustUID2將觸發全表掃描,因爲它沒有直接索引。另外,請小心使用子查詢,因爲我遇到了優化器無法完全優化子查詢的一些情況......在我的情況下,它足以將查詢拆分爲更多查詢(沒有子查詢) 。 它可能也有助於使用JOIN's,因爲它們的處理方式與子查詢不同。

0

一些隨機猜測:

(SELECT m.CustUID FROM mutualfriends m WHERE m.CustUID2 = '9:2'); 

...是可能不能夠有效地利用指數(CustUID,CustUID2)。你必須檢查解釋計劃。如果沒有,請考慮添加另一個單向索引(CustUID2,CustUID)。

表達式像

WHERE <constant> 
    OR <subquery> 

...生成甲骨文一個蹩腳的計劃。也許這也是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')