0

テーブルとデータを使用します。

CREATE TABLE test.tem(a INT,b INT,INDEX (a),INDEX (b));
INSERT INTO test.tem VALUES(1,2),(1,1),(1,NULL),(2,3);

データは次のようになります。

+------+------+
| a    | b    |
+------+------+
|    1 |    2 |
|    1 |    1 |
|    1 | NULL |
|    2 |    3 |
+------+------+

列 b を列 a ごとに min(b) グループに更新したいと考えています。
私が知っている正しい SQL の 1 つは次のとおりです。

UPDATE tem AS t1
  JOIN (SELECT a,MIN(b) AS m FROM tem GROUP BY a) AS t2
    USING (a)
SET t1.b = t2.m; 

正しい結果を生成するには、次のようにします。

+------+------+
| a    | b    |
+------+------+
|    1 |    1 |
|    1 |    1 |
|    1 |    1 |
|    2 |    3 |
+------+------+

ただし、この SQL クエリを使用して 450 万レコードの 1 つのテーブルを更新するには、約 5 分かかります。

だから、私は自分自身のSQLを1つ持っています:

UPDATE test.tem t1
  JOIN test.tem t2
    ON t1.a = t2.a
SET t1.b = t2.b
WHERE t1.b > t2.b
     OR t1.b IS NULL;

しかし、それは間違った結果を得ます:

+------+------+
| a    | b    |
+------+------+
|    1 |    1 |
|    1 |    1 |
|    1 |    2 |
|    2 |    3 |
+------+------+

その理由は、更新時の MYSQL の動作にあると思います。間違った結果がどのように出てくるか誰か教えてもらえますか? 誰かが私のSQL を修正できれば、それも役に立ちます。

4

2 に答える 2

2

クエリの実行速度を上げるためにできるなことの 1 つは、適切なインデックスを使用してWHERE/USING句を最適化することです。

UPDATE tem AS t1
  JOIN (SELECT a,MIN(b) AS m FROM tem GROUP BY a) AS t2
    USING (a)
SET t1.b = t2.m;

このリクエストにはUSING(a)句があります。a最速の MySQL は、最速のクエリが実行される列に一致することができます。したがって、その列にインデックスを追加する必要があります。

ALTER TABLE tem ADD INDEX (a);

実際のところ、サブクエリは と の両方GROUB BY(a)を使用してMIN(b)いるため、インデックス on(a,b)はおそらくさらに優れたパフォーマンスを発揮します。

ALTER TABLE tem ADD INDEX (a,b);

それを確認するために、クエリ プランを調べる必要がある場合があります (以下をEXPLAIN 参照)。


2 番目のクエリは次のとおりです。

UPDATE test.tem t1
  JOIN test.tem t2
    ON t1.a = t2.a
SET t1.b = t2.b
WHERE t1.b > t2.b
     OR t1.b IS NULL;

ここでは、「クエリの何が問題なのか」には答えません。bただし、純粋なパフォーマンスの観点からは、このクエリは句で列を使用するためWHERE、実行を最適化すると、少なくとも にインデックスを追加する必要がありますb

ALTER TABLE tem ADD INDEX (b);

ヒントとして、クエリが遅い 場合は、MySQL がインデックスを使用するかどうか、またはどのように使用するかを確認するために、クエリ プランを調べることができます。SELECTEXPLAIN SELECT ...

ここで 2 つのクエリをSELECTステートメントとして書き直すと、次のようになります。

EXPLAIN SELECT t1.b = t2.b
  FROM tem AS t1
  JOIN (SELECT a,MIN(b) AS m FROM tem GROUP BY a) AS t2
  USING (a);

EXPLAIN SELECT t1.b = t2.b
  FROM test.tem t1
  JOIN test.tem t2
  ON t1.a = t2.a
  WHERE t1.b > t2.b
     OR t1.b IS NULL;
于 2013-08-08T08:41:40.393 に答える