Postgres データベースのデータベース ビューを作成するために、風光明媚な宝石を適用しています。73k レコードの注文 (ops_orders) テーブルと、170k レコードの注文に属する注文明細 (ops_order_line_items) があります。
問題は、クエリの WITH ステートメントの実行時間が長すぎて、無期限にハングすることです。
WITH
excluded_order_ids AS (
SELECT ord.id
FROM ops_orders ord
WHERE NOT EXISTS (
SELECT 1
FROM ops_order_line_items oli
WHERE oli.processing_status != 6 -- PENDING
AND oli.order_id = ord.id
)
UNION ALL
SELECT ord.id
FROM ops_orders ord
WHERE NOT EXISTS (
SELECT 1
FROM ops_order_line_items oli
WHERE oli.processing_status != 1 -- FULFILLED
AND oli.order_id = ord.id
)
UNION ALL
SELECT ord.id
FROM ops_orders ord
WHERE NOT EXISTS (
SELECT 1
FROM ops_order_line_items oli
WHERE oli.processing_status != 4 -- CANCELLED
AND oli.order_id = ord.id
)
UNION ALL
SELECT ord.id
FROM ops_orders ord
WHERE NOT EXISTS (
SELECT 1
FROM ops_order_line_items oli
WHERE oli.line_item_type != 1 -- RESENT
AND oli.order_id = ord.id
)
),
included_order_ids AS (
SELECT ord.id
FROM ops_orders ord
WHERE NOT EXISTS (
SELECT 1
FROM ops_order_line_items oli
WHERE oli.processing_status != 3 -- PENDING
AND oli.deadline > (current_date + 1)
AND oli.order_id = ord.id
)
)
SELECT oli.*
FROM ops_order_line_items oli
JOIN ops_purchase_line_items pli ON pli.id = oli.purchase_line_item_id
JOIN ops_purchase_orders po ON po.id = pli.purchase_order_id
JOIN ops_orders ord ON ord.id = oli.order_id
WHERE ((oli.processing_status IN (0, 2) AND oli.deadline <= (current_date + 3)) -- status: ?, ORDERED
OR (oli.processing_status IN (5, 7) AND oli.deadline <= current_date) -- status: DROPSHIP, PACKING
OR (oli.processing_status IN (2) AND po.countdown_date > po.created_at) -- status: FULFILLED
OR (oli.order_id IN (SELECT id FROM included_order_ids)))
AND oli.order_id NOT IN (SELECT id FROM excluded_order_ids)
ORDER BY ord.order_number DESC, oli.created_at ASC
ただし、次のように変更すると、クエリは機能しました。
WITH
included_order_ids AS (
SELECT ord.id
FROM ops_orders ord
WHERE NOT EXISTS (
SELECT 1
FROM ops_order_line_items oli
WHERE oli.processing_status != 3 -- PENDING
AND oli.deadline > (current_date + 1)
AND oli.order_id = ord.id
)
)
SELECT oli.*
FROM ops_order_line_items oli
JOIN ops_purchase_line_items pli ON pli.id = oli.purchase_line_item_id
JOIN ops_purchase_orders po ON po.id = pli.purchase_order_id
JOIN ops_orders ord ON ord.id = oli.order_id
WHERE ((oli.processing_status IN (0, 2) AND oli.deadline <= (current_date + 3)) -- status: ?, ORDERED
OR (oli.processing_status IN (5, 7) AND oli.deadline <= current_date) -- status: DROPSHIP, PACKING
OR (oli.processing_status IN (2) AND po.countdown_date > po.created_at) -- status: FULFILLED
OR (oli.order_id IN (SELECT id FROM included_order_ids)))
AND oli.order_id NOT IN (
SELECT ord.id
FROM ops_orders ord
WHERE NOT EXISTS (
SELECT 1
FROM ops_order_line_items oli
WHERE oli.processing_status != 6 -- PENDING
AND oli.order_id = ord.id
))
AND oli.order_id NOT IN (
SELECT ord.id
FROM ops_orders ord
WHERE NOT EXISTS (
SELECT 1
FROM ops_order_line_items oli
WHERE oli.processing_status != 1 -- FULFILLED
AND oli.order_id = ord.id
))
AND oli.order_id NOT IN (
SELECT ord.id
FROM ops_orders ord
WHERE NOT EXISTS (
SELECT 1
FROM ops_order_line_items oli
WHERE oli.processing_status != 4 -- CANCELLED
AND oli.order_id = ord.id
))
AND oli.order_id NOT IN (
SELECT ord.id
FROM ops_orders ord
WHERE NOT EXISTS (
SELECT 1
FROM ops_order_line_items oli
WHERE oli.line_item_type != 1 -- RESENT
AND oli.order_id = ord.id
))
ORDER BY ord.order_number DESC, oli.created_at ASC
Postgres の WITH ステートメントのパフォーマンスは悪いですか? 調査しましたが、WITH ステートメントのパフォーマンスの低下について言及しているドキュメントは見つかりませんでした。分かりやすい解説お待ちしております。