5

postgres を使用して複数の行を更新しようとしています。次のコードを使用しています。

UPDATE foobar SET column_a = CASE
  WHEN column_b = '123' THEN 1
  WHEN column_b = '345' THEN 2
END;

新しいテーブルを作成すると問題なく動作しますが、これを 800 万行の大きなテーブルで実行すると、無期限にハングします。最初に Admineer (Web インターフェイス) とコンソールで試しました。

ただし、これは問題なく機能します。

UPDATE foobar SET column_a=1 WHERE column_b='123';

一度に何千もの更新があり、それらを 1 つのステートメントに入れたいので、このアプローチを自分のコードに実装することをためらっています。最初の例では postgres がハングし、2 番目の例では問題なく動作する理由について何か考えはありますか? 再確認したところ、テーブルにルールが適用されていません。

4

2 に答える 2

6

問題は..

ステートメント:

CASE
  WHEN column_b = '123' THEN 1
  WHEN column_b = '345' THEN 2
END;

.. は次の略です。

CASE
  WHEN column_b = '123' THEN 1
  WHEN column_b = '345' THEN 2
  ELSE NULL
END

つまり、WHERE句がない場合、UPDATEステートメントは単に「試行中」ではなく、実際にテーブル内のすべての行を更新し、そのほとんどをNULL.
おそらく、NOT NULL列の制約によりデータの損失が防止されました...

より良い解決策は..

一度に何千もの更新があるので、それらを 1 つのステートメントにまとめたいと思います。

大規模なセットの場合、はるかに高速(および短縮) :

UPDATE foobar f
SET    column_a = val.a
FROM  (
   VALUES
     (123, 1)
    ,(345, 2)
   ) val(b, a)
WHERE f.column_b = val.b

セットへの参加は、CASEすべての行のブランチの長いリストを簡単に繰り返すよりも優れていリストが長くなると、その差は急速に拡大します。

また、必ずいずれかの方法でインデックスを作成しcolumn_bてください。

VALUES適切な行を生成する任意のテーブル、ビュー、またはサブセレクトで式を置き換えることができます。

注:とは 型であると
想定しています。この場合、質問の前後の一重引用符は役に立ちませんでした。文字列リテラルの代わりに数値リテラルを使用することをお勧めします。(文字列リテラルでも機能しますが。)column_acolumn_binteger'123'

'123'タイプのデフォルトのような文字列リテラルunknown。数字が大きすぎる場合、 デフォルトの- または/
のような数値リテラル。123integerbigintnumeric

デフォルト以外のデータ型を扱っている場合は、明示的にキャストする必要があります。次のようになります。

...
FROM  (
   VALUES
     ('123'::sometype, '1'::sometype)  -- first row defines row type
    ,('345', '2')
   ) val(b, a)
...
于 2013-09-14T14:20:12.560 に答える
2

誰かがこの問題に遭遇した場合に備えて、私はこの質問を続けています。

このクエリが原因でした:

UPDATE foobar SET column_a = CASE
  WHEN column_b = '123' THEN 1
  WHEN column_b = '345' THEN 2
END;

問題は、WHERE ステートメントがないため、すべての行を更新しようとしていることです。大規模なデータベースでは、これが問題になる可能性があります。私の場合はタイムアウトになりました。そこに where ステートメントを追加するとすぐに、問題が修正されました。

解決策は次のとおりです。

UPDATE foobar SET column_a = CASE
   WHEN column_b = '123' THEN 1
   WHEN column_b = '345' THEN 2
END
WHERE column_b IN ('123','345')
于 2013-09-14T14:05:33.043 に答える