2012-04-12 87 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