2012-04-12 89 views
0

我們有龐大的數據庫MySQL查詢優化,我們有將近兩個湖泊記錄,而我們嘗試使用下面的查詢時間過長帶來的結果爲大型數據庫

更改爲MyQuery

SELECT 
     count(DISTINCT e.guid) AS total 
    FROM 
     elgg_entities e 
     JOIN elgg_users_entity u 
      ON e.guid = u.guid 
     JOIN (SELECT 
         subm1.*, 
         s1.string 
        FROM 
         elgg_metadata subm1 
         JOIN elgg_metastrings s1 
          ON subm1.value_id = s1.id) AS m1 
      ON e.guid = m1.entity_guid 
    WHERE 
      m1.name_id = '332' 
     AND m1.string LIKE '%96059%' 
     AND (( e.access_id = -2 
       AND e.owner_guid IN (SELECT guid_one 
             FROM elgg_entity_relationships 
             WHERE relationship = 'friend' 
              AND guid_two =130) 
      ) 
      OR 
      ( e.access_id IN (2, 1, 3, 4, 6, 7) 
       OR (e.owner_guid = 130) 
       OR ( e.access_id = 0 
        AND e.owner_guid = 130) 
      ) 
      AND e.enabled = 'yes' 
     ) 

my query explain

搜索

編輯,我們在循環中有更多的派生查詢,所以我需要關於@DRAPP的更多優化

答案

SELECT count(DISTINCT e.guid) AS total 
FROM elgg_entities e 
JOIN elgg_users_entity u ON e.guid = u.guid 
JOIN (

SELECT subm1 . * , s1.string 
FROM elgg_metadata subm1 
JOIN elgg_metastrings s1 ON subm1.value_id = s1.id 
) AS m1 ON e.guid = m1.entity_guid 
JOIN (

SELECT subm2 . * , s2.string 
FROM elgg_metadata subm2 
JOIN elgg_metastrings s2 ON subm2.value_id = s2.id 
) AS m2 ON e.guid = m2.entity_guid 
WHERE (
(
subm1.name_id = '332' 
AND s1.string LIKE '%10001%' 
) 
AND (
subm2.name_id = '328' 
AND s2.string LIKE '%New York%' 
) 
) 
AND (
(
e.access_id = -2 
AND e.owner_guid 
IN (

SELECT guid_one 
FROM elgg_entity_relationships 
WHERE relationship = 'friend' 
AND guid_two =2336 
) 
) 
OR (
e.access_id 
IN (2, 1) 
OR (
e.owner_guid =2336 
) 
OR (
e.access_id =0 
AND e.owner_guid =2336 
) 
) 
AND e.enabled = 'yes' 
) 
AND (
(
subm1.access_id = -2 
AND subm1.owner_guid 
IN (

SELECT guid_one 
FROM elgg_entity_relationships 
WHERE relationship = 'friend' 
AND guid_two =2336 
) 
) 
OR (
subm1.access_id 
IN (2, 1) 
OR (
subm1.owner_guid =2336 
) 
OR (
subm1.access_id =0 
AND subm1.owner_guid =2336 
) 
) 
AND subm1.enabled = 'yes' 
) 
AND (
(
subm2.access_id = -2 
AND subm2.owner_guid 
IN (

SELECT guid_one 
FROM elgg_entity_relationships 
WHERE relationship = 'friend' 
AND guid_two =2336 
) 
) 
OR (
subm2.access_id 
IN (2, 1) 
OR (
subm2.owner_guid =2336 
) 
OR (
subm2.access_id =0 
AND subm2.owner_guid =2336 
) 
) 
AND subm2.enabled = 'yes' 
) 

感謝

+0

盡你所能,你能描述你在試圖得到什麼,什麼是「近兩個湖記錄」? – DRapp 2012-04-17 18:45:49

回答

1

我已調整了您的查詢。一些where子句是冗餘的(關於e.owner_guid = 130),所以刪除了多餘的元素。

我已經添加了MySQL子句「STRAIGHT_JOIN」來告訴引擎按表和各個連接提供的順序執行。我以你的「m1」開始,作爲FIRST prequery還包括你的「name_id」和「String」限定詞的標準。確保您的elgg_metadata表在name_id列上具有索引。此外,由於您沒有對元數據或元字符串表中的任何其他列進行任何操作(除了限定),我只返回DISTINCT「entity_id」。這應該會爲您返回一個快速的小子集。

從這個結果中,只加入那些預先限定到您的實體,用戶和關係表(加入關係,因爲這是後來的「或」條件)。如果它在實體ID上找不到匹配項,請不要進一步詢問。

那麼,OR標準的其餘部分可以應用...如果owner_guid = 130或通過左連接與IN(子選擇符)找到eer(關係),那麼這將是一個性能殺手,或Access_ID。

SELECT STRAIGHT_JOIN 
     count(DISTINCT e.guid) AS total 
    FROM 
     (SELECT DISTINCT 
       subm1.entity_id 
      FROM 
       elgg_metadata subm1 
       JOIN elgg_metastrings s1 
        ON subm1.value_id = s1.id 
      WHERE 
        subm1.name_id = '332' 
       AND s1.string LIKE '%96059%') AS m1 

     JOIN elgg_entities e 
      ON m1.entity_id = e.guid 
      AND e.enabled = 'yes' 

      JOIN elgg_users_entity u 
       ON e.guid = u.guid 

      LEFT JOIN elgg_entity_relationships eer 
       ON e.owner_guid = eer.guid_one 
       AND eer.relationship = 'friend' 
       AND eer.guid_two = 130 
       AND e.access_id = -2 
    WHERE 
     e.owner_guid = 130 
     OR eer.guid_one = e.owner_guid 
     OR e.access_id IN (2, 1, 3, 4, 6, 7) 
+0

@selva,huh ???? – DRapp 2012-04-17 17:52:52

+0

你可以檢查這個鏈接http://stackoverflow.com/a/10196376/1329306 – selva 2012-04-17 18:39:02

+0

請檢查我的編輯查詢 – selva 2012-04-18 04:56:08