2011-12-22 5 views
2

私は長い間この問題に取り組んできました。このクエリは、小さなデータセットにかなり高速に動作しますが、テーブルには、それが実行に数分に30代から取る100K +行に育つとき:"nullではない"を使用する左結合クエリの最適化

SELECT accounts.id 
     , accounts.name 
     , ..etc.. 
FROM accounts 
     LEFT JOIN (
      SELECT distinct secr.record_id as id 
      FROM securitygroups secg 
        INNER JOIN securitygroups_users secu 
        ON secg.id = secu.securitygroup_id 
         AND secu.deleted = 0 
         AND secu.user_id = 'seed_chris_id' 
        INNER JOIN securitygroups_records secr 
        ON secg.id = secr.securitygroup_id 
         AND secr.deleted = 0 
         AND secr.module = 'Accounts' 
      WHERE secg.deleted = 0 
     ) securitygroup_join ON securitygroup_join.id = accounts.id 
WHERE ((accounts.assigned_user_id ='seed_chris_id' 
      OR securitygroup_join.id is not null)) 
     AND accounts.deleted=0 
ORDER BY 
     accounts.date_entered 
DESC LIMIT 0,21 

基本的にはユーザーがレコード(アカウントを所有しているすべての行を返す必要があります。 assigned_user_id)、またはレコードに関連付けられたグループのメンバーです(securitygroup_join.idはnullではありません)。この問合せは、フレームワークによって特定の方法で構築され、いくつかの制約に直面します。簡単に実装できない解決策は、これをUNIONに変更することです。そのルートを避けたいですか?過去には "where ... in"という句がありましたが、それはさらに悪化しました。必要に応じてjoin、where句を追加したり、インデックスを操作したりすることはできますが、クエリ構造の他の劇的な変更は簡単にはできません。

答えて

3

LEFT JOINの代わりにWHERE EXISTSを試すことができます。例:

SELECT accounts.id 
     , accounts.name 
     , ..etc.. 
FROM accounts 
WHERE ((accounts.assigned_user_id ='seed_chris_id' 
     OR EXISTS (SELECT 1 
        FROM securitygroups secg 
          INNER JOIN securitygroups_users secu 
          ON secg.id = secu.securitygroup_id 
           AND secu.deleted = 0 
           AND secu.user_id = 'seed_chris_id' 
          INNER JOIN securitygroups_records secr 
          ON secg.id = secr.securitygroup_id 
           AND secr.deleted = 0 
           AND secr.module = 'Accounts' 
         WHERE secr.record_id = accounts.id 
           AND secg.deleted = 0) 
     )) 
    AND accounts.deleted=0 
ORDER BY 
    accounts.date_entered 
DESC LIMIT 0,21 

私はこれをテストしていないため、パフォーマンスは向上するかもしれませんが、試してみる価値があります。

+0

+1:確かに試してみる価値があります。 – MatBailie

+0

securitygroups_recordsテーブルの700k行のデータベースに対して、提案された変更が約3.2秒で実行されていたのに対し、元のクエリが17.8秒で実行されていました。私はそれが良い改善だと思います:)。私は最初の場所に存在するとは思わなかった。ありがとう! – egg

+0

素晴らしい!お役に立てて嬉しいです。 –

関連する問題