Postgres 9.4では、次のクエリを頻繁に実行しています。
SELECT DISTINCT ON(recipient) * FROM messages
LEFT JOIN identities ON messages.recipient = identities.name
WHERE timestamp BETWEEN timeA AND timeB
ORDER BY recipient, timestamp DESC;
そこで、ビューを作成することにしました。
CREATE VIEW myView AS SELECT DISTINCT ON(recipient) * FROM messages
LEFT JOIN identities ON messages.recipient = identities.name
ORDER BY recipient, timestamp DESC;
SELECT * FROM myView WHERE timestamp BETWEEN timeA AND timeB
のようにビューをクエリすると、パフォーマンスが大幅に低下することに気づきました。
両方のクエリでEXPLAIN ANALYZE
を実行したところ、2番目のケースのデータベースがすべてのレコードを表示し、左結合を実行してからWHERE
句を適用していることがわかりました。つまり、WHERE
句はビューのクエリにプッシュダウンされません。また、ビューからORDER BY
を削除しようとしましたが、それでもデータベースは、フィルターされたセットではなく、完全なデータに対してLEFT JOIN
を実行します。
この動作の理由は何ですか?ビューを使用するときに同等のパフォーマンスを得る方法はありますか?
このような関数を作成できます。
CREATE OR REPLACE FUNCTION public.get_messages_by_timestamp (
time_a timestamp,
time_b timestamp
)
RETURNS TABLE (
recipient varchar,
"timestamp" timestamp
) AS
$$
BEGIN
RETURN QUERY
SELECT DISTINCT ON (m.recipient)
m.recipient,
m."timestamp"
FROM messages m
LEFT JOIN identities i ON m.recipient = i.name
WHERE
m."timestamp" BETWEEN time_a AND time_b
ORDER BY
m.recipient,
m."timestamp" DESC;
END;
$$
LANGUAGE 'plpgsql';
次に、テーブルのような関数を使用できます
SELECT *
FROM get_messages_by_timestamp('2015-01-01', '2015-01-02')