0

既存のシステムを更新していて、既に使用されているコードの一部に固執する必要があります。main_id ごとにテーブル n にレコードが存在しない場合もあれば、多数存在する場合もあります。main に約 40k レコード、n に約 330k レコードがあります。

過去 6 か月以内に n.date を持たないメインのレコードのみを選択する必要があります。

残念ながら、私が試したすべての方法は非常に遅くなりました。

main.main_id
main.field1
main.field2
main.field3

n.n_id
n.main_id
n.date
n.field1
n.field2
n.field3

クエリは次の形式です

SELECT distinct(main.main_id) FROM main LEFT JOIN...

ビュー、一時テーブル、インデックスの追加など、さまざまな場所にサブクエリを配置しようとしましたが、これまでのところ、妥当な速度に近いものはありませんでした。

残念ながら、私がこれまでに試したことのリストを持っていなかったので、それらを書き留めておらず、遅くなりました!

nから直接クエリを実行したのではないかと思います。はるかに高速になる可能性がありますが、それには大規模な書き直しが必要になります。クエリには他にも多くの要素がありますが、テーブルが結合されている場合は 2 秒未満で完了しますが、これはありません。

これは考えられる最も単純なもので、通常は WHERE 句と JOIN が多くなります。

EXPLAIN 
SELECT distinct(`main`.`main_id`),`morefields`,`morefields2`
FROM main LEFT JOIN anothertable ON anothertable    anothertable.a_n = main.a 
LEFT JOIN anothertable2 ON anothertable2.g_n = main.CG 
LEFT JOIN anothertable3 ON anothertable3.t_n = main.t 
LEFT JOIN (SELECT max(DateTS) as note_date, main_id FROM n GROUP BY main_id) n_sub ON main.main_id=n_sub.main_id
WHERE main.deleted = '0' 
AND n_sub.note_date < DATE_SUB(now(), INTERVAL 6 MONTH)
ORDER BY main.morefields ASC LIMIT 0, 30;
+----+-------------+-------------+--------+---------------+---------+---------+----------------------------+--------+----------------------------------------------+
| id | select_type | table       | type   | possible_keys | key     | key_len | ref                        | rows   | Extra                                        |
+----+-------------+-------------+--------+---------------+---------+---------+----------------------------+--------+----------------------------------------------+
|  1 | PRIMARY     | <derived2>  | ALL    | NULL          | NULL    | NULL    | NULL                       |  40324 | Using where; Using temporary; Using filesort |
|  1 | PRIMARY     | main    | eq_ref | PRIMARY       | PRIMARY | 4       | n_sub.cust_no          |      1 | Using where                                  |
|  1 | PRIMARY     | anothertable       | eq_ref | PRIMARY       | PRIMARY | 4       | db.maij.area          |      1 |                                              |
|  1 | PRIMARY     | anothertable2 | eq_ref | PRIMARY       | PRIMARY | 4       | db.main.CG |      1 |                                              |
|  1 | PRIMARY     | anothertable3  | eq_ref | PRIMARY       | PRIMARY | 4       | db.main.t          |      1 |                                              |
|  2 | DERIVED     | n  | index  | NULL          | main_id | 4       | NULL                       | 285961 |                                              |
+----+-------------+-------------+--------+---------------+---------+---------+----------------------------+--------+----------------------------------------------+
6 rows in set (30.25 sec)
4

2 に答える 2

0

これに基づいて:

+----+-------------+-------------+--------+---------------+---------+---------+--------------+--------+----------------------------------------------+
| id | select_type | table       | type   | possible_keys | key     | key_len | ref          | rows   | Extra                                        |
+----+-------------+-------------+--------+---------------+---------+---------+--------------+--------+----------------------------------------------+
|  1 | PRIMARY     |<derived2>   | ALL    | NULL          | NULL    | NULL    | NULL         |  40324 | Using where; Using temporary; Using filesort |
|  1 | PRIMARY     |main         | eq_ref | PRIMARY       | PRIMARY | 4       | n_sub.cust_no|      1 | Using where                                  |
|  1 | PRIMARY     |anothertable | eq_ref | PRIMARY       | PRIMARY | 4       | db.maij.area |      1 |                                              |
|  1 | PRIMARY     |anothertable2| eq_ref | PRIMARY       | PRIMARY | 4       | db.main.CG   |      1 |                                              |
|  1 | PRIMARY     |anothertable3| eq_ref | PRIMARY       | PRIMARY | 4       | db.main.t    |      1 |                                              |
|  2 | DERIVED     |n            | index  | NULL          | main_id | 4       | NULL         | 285961 |                                              |
+----+-------------+-------------+--------+---------------+---------+---------+--------------+--------+----------------------------------------------+

... インデックスに問題があるように見えます。たとえば、最初の行は、40,324 行全体をスキャンしてデータを取得していることを示しています。keyさらに悪いことに、クエリ ( ) でインデックスが指定されていないため、インデックス (列)が使用されていないように見えますpossible_keys

これを試してみるか、または同様のことを試してみてください (私が間違っていない限り)。ただし、実際のデータベースに変更を加える前に、必ずデータベースのバックアップ コピーで試してください。

ALTER TABLE `main` ADD INDEX ( `main_id` )

編集:

それでも問題が解決しない場合、次の提案は次の行を変更することです。

LEFT JOIN (SELECT max(DateTS) as note_date, main_id FROM n GROUP BY main_id) n_sub ON main.main_id=n_sub.main_id

このようなものに:

LEFT JOIN (SELECT max(DateTS) as note_date, main_id FROM n GROUP BY main_id) n_sub ON main.main_id=n_sub.main_id AND n_sub.note_date < DATE_SUB(now(), INTERVAL 6 MONTH)

この行を完全に削除できるようにする必要があります。

AND n_sub.note_date < DATE_SUB(now(), INTERVAL 6 MONTH)

別の可能性は、代わりにこれを試すことです:

SELECT distinct(`main`.`main_id`),`morefields`,`morefields2`
FROM main
-- Maybe change the next line to an INNER JOIN..?
LEFT JOIN n ON main.main_id = n.main_id
LEFT JOIN anothertable ON anothertable.a_n = main.a 
LEFT JOIN anothertable2 ON anothertable2.g_n = main.CG 
LEFT JOIN anothertable3 ON anothertable3.t_n = main.t 
WHERE main.deleted = '0'
GROUP BY main.main_id HAVING MAX(n.DateTS) < DATE_SUB(NOW(), INTERVAL 6 MONTH)
ORDER BY main.morefields ASC LIMIT 0, 30;
于 2013-09-30T06:29:14.430 に答える
0

過去 6 か月以内の FOR アクティビティを検索する左結合に基づいて、過去 6 か月の日付レコードがない ID のリストを完全かつ簡単に取得し、その結合の NULL に WHERE 句を適用できる必要があります。

SELECT 
      m.main_id,
      m.a,
      m.CG,
      m.t,
      m.morefields,
      m.morefields2,
   from
      main m
         left join n
            ON m.main_id = n.main_id
            and n.note_date > date_sub( now(), interval 6 month )
   where
          m.deleted = '0'
      AND n.main_id is null
   order by 
      m.morefields asc
   limit
      0, 30

これで、それらの結合からもフィールドが必要になる可能性がある他の結合ができました。もしそうなら、私は上記をラップし、それを結合の基礎として使用します...私はエイリアス「PQ」を使用して、残りの結合に対する「PreQuery」を識別します。

select 
      PQ.*,
      A_T1.SomeField(s),
      A_T2.SomeField(s),
      A_T3.SomeField(s)
   from 
      ( entire first query ) as PQ
         left join anothertable A_T1
            on PQ.a = A_T1.a_n
         left join anothertable2 A_T2
            on PQ.CG = A_T2.g_n
         left join anothertable2 A_T3
            on PQ.CG = A_T3.t

内部クエリには 30 の制限が適用されているため、制限を再度適用する必要はありません (「別の」テーブルがいくつかのデカルト結果を引き起こし、単一のメイン ID ごとにより多くのレコードを生成しない限り)。

実際のデータ/コンテキストを明らかに隠すために、実際に参加している実際の列について推測しているだけです。

于 2013-09-30T02:05:44.890 に答える