すでに述べたように、RETURNING
INSERT
の句 挿入された行のみが表示されます。具体的には、ここでマニュアルを引用 :
太字
したがって、相関サブクエリを追加することを妨げるものは何もありません。 RETURNING
へ リスト:
INSERT INTO employees.password_resets AS ep
(empl_pwd_reset_uuid , empl_user_pvt_uuid , t_valid , for_empl_user_pvt_uuid, token)
SELECT 'f70a0346-a077-11eb-bd1a-aaaaaaaaaaaa', '6efc2b7a-f27e-11ea-b66c-de1c405de048', '2021-04-18 19:57:47.111365', eu.empl_user_pvt_uuid , '19d65aea-7c4a-41bc-b580-9d047f1503e6'
FROM employees.users eu
WHERE empl_user_pub_uuid = 'e2bb39f1f28011eab66c63cb4d9c7a34'
RETURNING for_empl_user_pvt_uuid AS empl_user_pvt_uuid -- alias to meet your org. query
, (SELECT email
FROM employees.emails
WHERE empl_user_pvt_uuid = ep.empl_user_pvt_uuid
ORDER BY t DESC -- NULLS LAST ?
LIMIT 1
) AS email
, (SELECT name_first
FROM employees.profiles
WHERE empl_user_pvt_uuid = ep.empl_user_pvt_uuid
-- ORDER BY ???
LIMIT 1
) AS name_first;
これもはるかに効率的です 複数の理由で、あなたが持っていたクエリ(または提案されたもの)よりも。
-
サブクエリ
ee
は実行しません およびep
テーブルのすべての行にわたってemployees.emails
およびemployees.profiles
。これらのテーブルの主要部分が必要な場合は効率的ですが、それぞれから対象の1行のみをフェッチします。適切なインデックスがあれば、相関サブクエリはこれに対してはるかに効率的です。参照: -
1つ以上のCTEのオーバーヘッドを追加しません。
-
後にのみ追加データをフェッチします 成功した
INSERT
、したがって、何らかの理由でインサートが通過しなかった場合でも、時間を無駄にすることはありません。 (上部の引用を参照してください!)
さらに、おそらく最も重要なのは、これが正しいことです。 。実際に挿入された行のデータを使用します-後 それを挿入します。 (上部の引用を参照してください!)可能なデフォルト値の後、トリガーまたはルールが適用されました。私たちが見ているのは、実際にデータベースにあるもの(現在)であると確信できます。
ORDER BY
はありません profiles.name_first
の場合 。そうではありません。修飾行が1つしかない場合は、DISTINCT
は必要ありません。 LIMIT 1
。または、複数存在する可能性がある場合は、決定論的なORDER BY
も必要です。 決定論的な結果を得るには。
そして、emails.t
NULLにすることができます。NULLS LAST
を追加する必要があります ORDER BY
で 句。参照:
インデックス
理想的には、次の複数列のインデックスがあります(列はこの順序で):
-
users (empl_user_pub_uuid, empl_user_pvt_uuid)
-
emails (empl_user_pvt_uuid, email)
-
profiles (empl_user_pvt_uuid, name_first)
次に、テーブルが十分に真空になっている場合、インデックスのみのスキャンが3回行われ、操作全体が高速になります。
事前に取得-INSERT
値?
本当に必要な場合(私はそうは思わない)、次のことを検討してください。