94

CLI スクリプトを使用して、大きな MyISAM テーブル (2,500 万レコード) を更新しようとしています。テーブルは他のものによってロック/使用されていません。

各レコードに対して単一の UPDATE クエリを実行する代わりに、CASE 機能を利用することも考えました。

idフィールドは PRIMARY です。次のクエリには数ミリ秒かかると思います。

UPDATE `table` SET `uid` = CASE
    WHEN id = 1 THEN 2952
    WHEN id = 2 THEN 4925
    WHEN id = 3 THEN 1592
    END

見よ、クエリは CPU を占有し、永久に終了しません。

その後、驚いたことに、クエリが 2,500 万行すべてを更新していて、指定していない行に NULL が設定されていることがわかりました。

その目的は何ですか?このクエリを実行するたびに 2,500 万行を更新せずに、特定の行に対して MASS 更新を行うことはできますか? それとも、個々の更新を行ってからコミットする必要がありますか?

4

3 に答える 3

192

これを試して

UPDATE `table` SET `uid` = CASE
    WHEN id = 1 THEN 2952
    WHEN id = 2 THEN 4925
    WHEN id = 3 THEN 1592
    ELSE `uid`
    END
WHERE id  in (1,2,3)
于 2012-10-05T21:46:37.187 に答える
7

が 1 から順番に始まる場合id、最も単純な (そして最も速い) のは次のようになります。

UPDATE `table` 
SET uid = ELT(id, 2952, 4925, 1592) 
WHERE id IN (1,2,3)

ELT()は文字列のリストの N 番目の要素を返すため、N = 1 の場合は str1、N = 2 の場合は str2 などです。N が 1 未満または引数の数より大きい場合は NULL を返します。

明らかに、上記のコードidは 1、2、または 3 の場合idにのみ機能します。10、20、または 30 の場合、次のいずれかが機能します。

UPDATE `table` 
SET uid = CASE id 
WHEN 10 THEN 2952 
WHEN 20 THEN 4925 
WHEN 30 THEN 1592 END CASE 
WHERE id IN (10, 20, 30)

またはより簡単:

UPDATE `table` 
SET uid = ELT(FIELD(id, 10, 20, 30), 2952, 4925, 1592) 
WHERE id IN (10, 20, 30)

FIELD()は、str1、str2、 str3 、... リスト内の str のインデックス (位置) を返します。str が見つからない場合は 0 を返します。

于 2012-10-05T21:50:04.847 に答える
5

ELSEを見逃したからです。

「真である最初の条件の結果を返します。一致する結果値がなかった場合、ELSE の後の結果が返されます。ELSE 部分がない場合は NULL が返されます。」( http://dev.mysql.com/doc/refman/5.0/en/control-flow-functions.html#operator_case )

于 2012-10-05T21:51:48.573 に答える