编写这个mysql select查询的更好方法

时间:2012-12-05 19:01:36

标签: mysql

我有一个很长的查询,它正在切换资源并需要重写它。 它的一个明显问题是在where子句中使用“not in”。 我最初的想法是重写它,取消所有自连接并在子查询上执行“不存在”。是否有任何关于这样做的想法,或者是一个比那个更有效的想法?

以下是查询:

SELECT a.referenceid,
       a.memberid AS d1,
       b.memberid AS d2,
       c.memberid AS d3,
       d.memberid AS d4,
       e.memberid AS d5,
       f.memberid AS d6
FROM   jos_comprofiler_members AS a FORCE INDEX (aprm)
       LEFT JOIN jos_comprofiler_members AS b FORCE INDEX (aprm)
              ON a.memberid = b.referenceid
                 AND b.accepted = 1
                 AND b.pending = 0
       LEFT JOIN jos_comprofiler_members AS c FORCE INDEX (aprm)
              ON b.memberid = c.referenceid
                 AND c.accepted = 1
                 AND c.pending = 0
       LEFT JOIN jos_comprofiler_members AS d FORCE INDEX (pamr)
              ON c.memberid = d.referenceid
                 AND d.accepted = 1
                 AND d.pending = 0
       LEFT JOIN jos_comprofiler_members AS e FORCE INDEX (pamr)
              ON d.memberid = e.referenceid
                 AND e.accepted = 1
                 AND e.pending = 0
       LEFT JOIN jos_comprofiler_members AS f FORCE INDEX (pamr)
              ON e.memberid = f.referenceid
                 AND f.accepted = 1
                 AND f.pending = 0
WHERE  a.referenceid = 1593
       AND a.accepted = 1
       AND a.pending = 0
       AND f.memberid = 1593
       AND b.memberid NOT IN ( 1593, a.memberid )
       AND c.memberid NOT IN ( 1593, a.memberid, b.memberid )
       AND d.memberid NOT IN ( 1593, a.memberid, b.memberid, c.memberid )
       AND e.memberid NOT IN (
           1593, a.memberid, b.memberid, c.memberid, d.memberid )
       AND f.memberid NOT IN ( 1593, a.memberid, b.memberid, c.memberid,
                               d.memberid, e.memberid )
LIMIT  0, 1  

1 个答案:

答案 0 :(得分:0)

您的查询正在寻找1593年距离6内的所有成员。修辞问题:这与六度分离有关吗?

通常,在SQL中查找此类列表需要递归查询或一些非SELECT构造(循环,游标)。当列表由变量成员组成时,我不确定MySQL如何处理not in。但是,我怀疑它正在为每一个进行某种嵌套循环连接。

建议:将not in语句移至on子句。例如:

   LEFT JOIN jos_comprofiler_members AS c FORCE INDEX (aprm)
          ON b.memberid = c.referenceid
             AND c.accepted = 1
             AND c.pending = 0
             AND (c.memberId <> b.MemberId an c.MemberId <> a.MemberId and c.MemberId <> 1593)

这可以改善一些事情。或者让他们变得更糟。但这是一个想法。