0

重複する値を持つ最初のレコードを除くすべてを検索するための、このかなり非常識なクエリがあります。38000レコードで実行するには、かなり長い時間がかかります。約50秒。

UPDATE exr_exrresv
    SET mh_duplicate = 1
WHERE exr_exrresv._id IN
(
     SELECT F._id
     FROM exr_exrresv AS F
     WHERE Exists 
     (
          SELECT PHONE_NUMBER, 
                 Count(_id)
          FROM exr_exrresv
          WHERE exr_exrresv.PHONE_NUMBER = F.PHONE_NUMBER 
                AND exr_exrresv.PHONE_NUMBER != '' 
                AND mh_active = 1 AND mh_duplicate = 0
          GROUP BY exr_exrresv.PHONE_NUMBER
          HAVING Count(exr_exrresv._id) > 1)
     )
AND exr_exrresv._id NOT IN
(
   SELECT Min(_id)
   FROM exr_exrresv AS F
   WHERE Exists 
   (
       SELECT PHONE_NUMBER,
       Count(_id)
       FROM exr_exrresv
       WHERE exr_exrresv.PHONE_NUMBER = F.PHONE_NUMBER 
             AND exr_exrresv.PHONE_NUMBER != '' 
             AND mh_active = 1 
             AND mh_duplicate = 0
       GROUP BY exr_exrresv.PHONE_NUMBER
       HAVING Count(exr_exrresv._id) > 1
   )
       GROUP BY PHONE_NUMBER
);

それを最適化する方法や、どのように始めるべきかについてのヒントはありますか?クエリプランを確認しましたが、改善を開始する方法がよくわかりません。一時テーブル?より良いクエリ?

Explainクエリプランの出力は次のとおりです。

0|0|0|SEARCH TABLE exr_exrresv USING INTEGER PRIMARY KEY (rowid=?) (~12 rows)
0|0|0|EXECUTE LIST SUBQUERY 0
0|0|0|SCAN TABLE exr_exrresv AS F (~500000 rows)
0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 1
1|0|0|SEARCH TABLE exr_exrresv USING AUTOMATIC COVERING INDEX (PHONE_NUMBER=? AND mh_active=? AND mh_duplicate=?) (~7 rows)
1|0|0|USE TEMP B-TREE FOR GROUP BY
0|0|0|EXECUTE LIST SUBQUERY 2
2|0|0|SCAN TABLE exr_exrresv AS F (~500000 rows)
2|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 3
3|0|0|SEARCH TABLE exr_exrresv USING AUTOMATIC COVERING INDEX (PHONE_NUMBER=? AND mh_active=? AND mh_duplicate=?) (~7 rows)
3|0|0|USE TEMP B-TREE FOR GROUP BY
2|0|0|USE TEMP B-TREE FOR GROUP BY

ヒントをいただければ幸いです。:)

また、私はRubyを使用してSQLクエリを作成しているので、ロジックがSQLを離れてRubyで記述される方が理にかなっている場合は、それが可能です。

スキーマは次のとおりです。ここでsqlfiddleを使用できます:http ://sqlfiddle.com/#!2/2c07e

_id INTEGER PRIMARY KEY
OPPORTUNITY_ID varchar(50)
CREATEDDATE varchar(50)
FIRSTNAME varchar(50)
LASTNAME varchar(50)
MAILINGSTREET varchar(50)
MAILINGCITY varchar(50)
MAILINGSTATE varchar(50)
MAILINGZIPPOSTALCODE varchar(50)
EMAIL varchar(50)
CONTACT_PHONE varchar(50)
PHONE_NUMBER varchar(50)
CallFromWeb varchar(50)
OPPORTUNITY_ORIGIN varchar(50)
PROJECTED_LTV varchar(50)
MOVE_IN_DATE varchar(50)
mh_processed_date varchar(50)
mh_control INTEGER
mh_active INTEGER
mh_duplicate INTEGER
4

2 に答える 2

1

あなたの投稿から推測するmh_duplicateと、その電話番号を持つ最初のレコードではない場合、同じ電話番号を持つレコードの列を更新しようとしているように見えますか?

それが正しければ、更新する ID が取得されるはずです (適切な where 基準を追加し直す必要がある場合があります)。そこから、更新は簡単です。

SELECT e._Id
FROM exr_exrresv e
JOIN
 ( SELECT t.Phone_Number
    FROM exr_exrresv t
    GROUP BY t.Phone_Number
    HAVING COUNT (t.Phone_Number) > 1
  ) e2 ON e.Phone_Number = e2.Phone_Number
LEFT JOIN 
 ( SELECT MIN(t2._Id) as KeepId
    FROM exr_exrresv t2
    GROUP BY t2.Phone_Number
  ) e3 ON e._Id = e3.KeepId
WHERE e3.KeepId is null

そしてSQLフィドル

幸運を。

于 2013-01-21T07:30:17.793 に答える
1

これは、一致する phone_number とより少ない _id を持つアクティブなレコードが存在する場合、レコードの重複と見なされます。(グループ化やカウントは必要ありません。)

update exr_exrresv
    set mh_duplicate = 1
where exr_exrresv._id in (
  select target._id
  from exr_exrresv as target
  where target.phone_number != ''
  and target.mh_active = 1
  and exists (
    select null from exr_exrresv as probe
    where probe.phone_number = target.phone_number 
    and probe.mh_active = 1
    and probe._id < target._id
  )
)

このクエリは、phone_number にインデックスが存在する場合に非常に役立ちます。理想的にはexr_exrresv (phone_number, _id)

SQLフィドル

于 2013-01-21T08:06:55.460 に答える