sql >> データベース >  >> RDS >> PostgreSQL

INSERT / UPDATE/DELETE操作を最適化する

    変更されたテーブル定義

    これらの列を本当にNOT NULLにする必要がある場合 本当に必要なのは文字列'default' engine_slugのデフォルトとして 、列のデフォルトを導入することをお勧めします:

    COLUMN           |          TYPE           |      Modifiers
    -----------------+-------------------------+---------------------
     id              | INTEGER                 | NOT NULL DEFAULT ... 
     engine_slug     | CHARACTER VARYING(200)  | NOT NULL DEFAULT 'default'
     content_type_id | INTEGER                 | NOT NULL
     object_id       | text                    | NOT NULL
     object_id_int   | INTEGER                 |
     title           | CHARACTER VARYING(1000) | NOT NULL
     description     | text                    | NOT NULL DEFAULT ''
     content         | text                    | NOT NULL
     url             | CHARACTER VARYING(1000) | NOT NULL DEFAULT ''
     meta_encoded    | text                    | NOT NULL DEFAULT '{}'
     search_tsv      | tsvector                | NOT NULL
     ...

    DDLステートメントは次のようになります:

    ALTER TABLE watson_searchentry ALTER COLUMN  engine_slug DEFAULT 'default';
    

    など

    そうすれば、それらの値を毎回手動で挿入する必要はありません。

    また、object_id text NOT NULL, object_id_int INTEGER ?それは変です。理由があると思います...

    更新された要件に対応します:

    もちろん、あなたはしなければならない UNIQUEを追加します 要件を強制するための制約:

    ALTER TABLE watson_searchentry
    ADD CONSTRAINT ws_uni UNIQUE (content_type_id, object_id_int)
    

    付随するインデックスが使用されます。初心者のためのこのクエリによって。

    ところで、私はvarchar(n)をほとんど使用しません Postgresで。 text1つの理由があります。

    データ変更CTEを使用したクエリ

    これは、「書き込み可能な」CTEとも呼ばれるデータ変更共通テーブル式を使用した単一のSQLクエリとして書き直すことができます。 Postgres 9.1以降が必要です。
    さらに、このクエリは削除する必要があるものだけを削除し、更新できるものを更新します。

    WITH  ctyp AS (
       SELECT id AS content_type_id
       FROM   django_content_type
       WHERE  app_label = 'web'
       AND    model = 'member'
       )
    , sel AS (
       SELECT ctyp.content_type_id
             ,m.id       AS object_id_int
             ,m.id::text AS object_id       -- explicit cast!
             ,m.name     AS title
             ,concat_ws(' ', u.email,m.normalized_name,c.name) AS content
             -- other columns have column default now.
       FROM   web_user    u
       JOIN   web_member  m  ON m.user_id = u.id
       JOIN   web_country c  ON c.id = m.country_id
       CROSS  JOIN ctyp
       WHERE  u.is_active
       )
    , del AS (     -- only if you want to del all other entries of same type
       DELETE FROM watson_searchentry w
       USING  ctyp
       WHERE  w.content_type_id = ctyp.content_type_id
       AND    NOT EXISTS (
          SELECT 1
          FROM   sel
          WHERE  sel.object_id_int = w.object_id_int
          )
       )
    , up AS (      -- update existing rows
       UPDATE watson_searchentry 
       SET    object_id = s.object_id
             ,title     = s.title
             ,content   = s.content
       FROM   sel s
       WHERE  w.content_type_id = s.content_type_id
       AND    w.object_id_int   = s.object_id_int
       )
                   -- insert new rows
    INSERT  INTO watson_searchentry (
            content_type_id, object_id_int, object_id, title, content)
    SELECT  sel.*  -- safe to use, because col list is defined accordingly above
    FROM    sel
    LEFT    JOIN watson_searchentry w1 USING (content_type_id, object_id_int)
    WHERE   w1.content_type_id IS NULL;
    
    • django_content_typeのサブクエリ 常に単一の値を返しますか?それ以外の場合、CROSS JOIN トラブルの原因になります。

    • 最初のCTEsel 挿入する行を収集します。 一致する列名を選択する方法に注意してください 物事を単純化するため。

    • CTEのdel 更新可能な行を削除することは避けています。

    • CTEでup それらの行は代わりに更新されます。

    • したがって、以前に削除されなかった行を最後のINSERTに挿入することは避けます。 。

    繰り返し使用するためにSQLまたはPL/pgSQL関数に簡単にラップできます。

    大量の同時使用には安全ではありません。あなたが持っていた機能よりもはるかに優れていますが、それでも同時書き込みに対して100%堅牢ではありません。しかし、更新された情報によると、それは問題ではありません。

    UPDATEをDELETEおよびINSERTに置き換えると、コストが大幅に高くなる場合とそうでない場合があります。 MVCCにより、内部的にすべてのUPDATEで新しい行バージョンが生成されます。モデル

    スピードファースト

    古い行を保持することにあまり関心がない場合は、より単純なアプローチの方が速い場合があります。すべてを削除して、新しい行を挿入します。また、plpgsql関数にラップすることで、計画のオーバーヘッドを少し節約できます。あなたの関数は基本的に、いくつかのマイナーな簡略化と上記で追加されたデフォルトの遵守を伴います:

    CREATE OR REPLACE FUNCTION update_member_search_index()
      RETURNS VOID AS
    $func$
    DECLARE
       _ctype_id int := (
          SELECT id
          FROM   django_content_type
          WHERE  app_label='web'
          AND    model = 'member'
          );  -- you can assign at declaration time. saves another statement
    BEGIN
       DELETE FROM watson_searchentry
       WHERE content_type_id = _ctype_id;
    
       INSERT INTO watson_searchentry
             (content_type_id, object_id, object_id_int, title, content)
       SELECT _ctype_id, m.id, m.id::int,m.name
             ,u.email || ' ' || m.normalized_name || ' ' || c.name
       FROM   web_member  m
       JOIN   web_user    u USING (user_id)
       JOIN   web_country c ON c.id = m.country_id
       WHERE  u.is_active;
    END
    $func$ LANGUAGE plpgsql;
    

    concat_ws() NULLに対して安全です 値を設定してコードを単純化しますが、単純な連結よりも少し遅くなります。

    また:

    トリガーが必要なのがこれだけの場合は、ロジックをこの関数に組み込む方が高速です。そうでなければ、大騒ぎする価値はおそらくないでしょう。




    1. mysql_secure_installationを使用する目的は何ですか?

    2. Oracle21cをSQLServerに接続する

    3. ステートメントオブジェクトが設定されていない場合、PDOStatement ::closeCursor()を呼び出す必要がありますか?

    4. プロプライエタリデータベースからオープンソースデータベースに移行するためのヒント