ハードウェアの性能
- CPU: 高速なCPUは、インデックスの更新やデータの挿入処理を迅速に行います。
- メモリ: 十分なメモリは、データベースが多くのデータをキャッシュに保持することを可能にし、ディスクI/Oを減少させます。
- ストレージ: SSDはHDDよりも高速な読み書きを提供し、挿入およびインデックスの更新速度を向上させます。
PostgreSQLの設定
- shared_buffers: PostgreSQLが使用する共有バッファのサイズ。大きいほどデータをメモリに保持できるため、I/Oパフォーマンスが向上します。
- work_mem: ソートやハッシュ操作に使用されるメモリのサイズ。クエリのパフォーマンスに影響します。
- maintenance_work_mem: インデックス作成やVACUUM操作などに使用されるメモリのサイズ。
- wal_buffers: Write-Ahead Logging(WAL)のバッファサイズ。トランザクションログの書き込み性能に影響します。
- checkpoint_completion_target: チェックポイントの完了目標時間。これを調整することでディスクI/Oのピークを緩和できます。
- autovacuum: 自動バキュームの設定。デッドタプルの削除を定期的に行い、テーブルとインデックスの肥大化を防ぎます。
PostgreSQLのバージョン
- 機能と最適化: 新しいバージョンではパフォーマンスの最適化や新機能が追加されることが多いです。最新バージョンを使用することで恩恵を受けることができます。
データベース設計
- インデックスの数と種類: 適切なインデックス設計は検索パフォーマンスを向上させますが、過剰なインデックスは挿入・更新・削除操作のパフォーマンスを低下させます。
- パーティショニング: 大規模なテーブルをパーティションに分割することで、特定のクエリや挿入操作のパフォーマンスを向上させることができます。
- テーブルとインデックスのサイズ: 大きなテーブルやインデックスでは挿入操作のオーバーヘッドが大きくなります。
データの特性
- データの分布: インデックスの効果はデータの分布によって異なります。均一な分布はB-treeインデックスに適しています。
- データの頻繁な変更: 頻繁な挿入・更新・削除操作がある場合、インデックスのオーバーヘッドが蓄積されるため、パフォーマンスに影響を与える可能性があります。
その他の要因
- ネットワークの遅延: リモートデータベースにアクセスする場合、ネットワーク遅延が全体のパフォーマンスに影響を与えます。
- 並行性とロック: 高い並行アクセスがある場合、ロックの競合が発生し、パフォーマンスに影響を与える可能性があります。
結論
PostgreSQLの性能は多くの要因に依存します。適切なハードウェアの選択、最適なPostgreSQL設定、適切なデータベース設計、および最新バージョンの使用は、データ挿入時のパフォーマンスを最大限に引き出すために重要です。これらの要因を考慮して、インデックスのオーバーヘッドを最小限に抑え、データベースの全体的なパフォーマンスを向上させることができます。
4o
postgresの設定でベストプラクティスな値の事例を教えてChatGPT
PostgreSQLの設定は、ハードウェア、ワークロード、データベースの規模、使用ケースに依存します。しかし、一般的なベストプラクティスとして推奨される設定値の事例を以下に示します。これらの設定は基本的なガイドラインであり、実際の環境に合わせて調整が必要です。
shared_buffers
- 推奨値: サーバーの物理メモリの25%〜40%
- 例: 64GBのメモリがあるサーバーの場合、
shared_buffers = 16GB
- 説明: PostgreSQLが使用する共有メモリのサイズ。大きいほどディスクI/Oを減少させ、パフォーマンスが向上するが、過剰に大きいとOSのキャッシュと競合する可能性がある。
work_mem
- 推奨値: クエリごとに使用される一時メモリのサイズを設定。大規模な並列クエリの場合、少なめに設定する。
- 例:
work_mem = 4MB
から64MB
まで。大規模な分析クエリを実行する場合はさらに増やすことを検討。 - 説明: ソートやハッシュ操作に使用されるメモリ。十分なメモリを割り当てることでディスクI/Oを減少させ、パフォーマンスが向上する。
maintenance_work_mem
- 推奨値: 1GB〜4GB
- 例:
maintenance_work_mem = 2GB
- 説明: VACUUM、CREATE INDEX、ALTER TABLEなどのメンテナンス作業に使用されるメモリ。大きいほどこれらの操作が高速に実行される。
wal_buffers
- 推奨値: 16MB〜64MB
- 例:
wal_buffers = 16MB
- 説明: WAL (Write-Ahead Logging) のバッファサイズ。デフォルトは通常十分だが、大規模な書き込みワークロードの場合、増加させることで性能が向上する場合がある。
checkpoint_completion_target
- 推奨値: 0.7〜0.9
- 例:
checkpoint_completion_target = 0.8
- 説明: チェックポイントの完了目標時間。高めに設定することで、チェックポイントによるI/Oのピークを緩和し、スムーズな動作を実現する。
effective_cache_size
- 推奨値: サーバーの物理メモリの50%〜75%
- 例: 64GBのメモリがあるサーバーの場合、
effective_cache_size = 48GB
- 説明: PostgreSQLのクエリプランナーが利用可能なキャッシュサイズを推定するための設定。大きく設定することで、クエリプランが効率的になる。
autovacuum関連設定
- autovacuum_max_workers: サーバーのコア数に応じて設定。
- 例:
autovacuum_max_workers = 3
- 例:
- autovacuum_naptime: バキュームプロセスの休止時間。デフォルトの60秒は適切。
- 例:
autovacuum_naptime = 60s
- 例:
- autovacuum_vacuum_scale_factor: テーブルのサイズに応じて調整。大規模テーブルには小さめに設定。
- 例:
autovacuum_vacuum_scale_factor = 0.1
- 例:
- autovacuum_analyze_scale_factor: テーブルのサイズに応じて調整。
- 例:
autovacuum_analyze_scale_factor = 0.05
- 例:
その他の重要な設定
- max_connections: サーバーの性能とアプリケーションの要件に応じて設定。
- 例:
max_connections = 100
〜500
- 例:
- default_statistics_target: クエリプランの精度を向上させるために設定。大きくすることで分析クエリのパフォーマンスが向上する場合がある。
- 例:
default_statistics_target = 100
- 例:
例としての設定
postgresqlコードをコピーするshared_buffers = 16GB
work_mem = 64MB
maintenance_work_mem = 2GB
wal_buffers = 16MB
checkpoint_completion_target = 0.8
effective_cache_size = 48GB
autovacuum_max_workers = 3
autovacuum_naptime = 60s
autovacuum_vacuum_scale_factor = 0.1
autovacuum_analyze_scale_factor = 0.05
max_connections = 200
default_statistics_target = 100
調整のためのベンチマーク
設定変更後は、必ずベンチマークやモニタリングツールを使用してパフォーマンスを評価し、必要に応じて設定を微調整してください。具体的には、pg_stat_statements
ビューやpg_stat_activity
ビューを使用してクエリのパフォーマンスやリソース使用状況を監視します。
まとめ
PostgreSQLのパフォーマンスを最適化するための設定は、使用するハードウェア、ワークロード、およびデータベースの特性に依存します。上記の推奨設定値を参考に、自分の環境に合わせて適切に調整してください。また、設定変更後は必ずパフォーマンスのベンチマークを行い、効果を確認することが重要です。
4o
pg_stat_statementsビューやpg_stat_activityのクエリを教えてChatGPT
PostgreSQLのpg_stat_statements
ビューやpg_stat_activity
ビューは、データベースのパフォーマンスを監視し、クエリの動作を分析するために非常に有用です。以下に、それぞれのビューを使用するためのクエリの例を示します。
pg_stat_statements
ビュー
pg_stat_statements
は、クエリの統計情報を収集する拡張機能です。この拡張機能を使用するには、事前にインストールし、有効化する必要があります。
拡張機能の有効化
sqlコードをコピーするCREATE EXTENSION pg_stat_statements;
サンプルクエリ
- 最も頻繁に実行されたクエリのリスト
SELECT query, calls, total_time, rows, mean_time, stddev_time, min_time, max_time FROM pg_stat_statements ORDER BY calls DESC LIMIT 10;
- 合計実行時間が最も長いクエリのリスト
SELECT query, calls, total_time, rows, mean_time, stddev_time, min_time, max_time FROM pg_stat_statements ORDER BY total_time DESC LIMIT 10;
- 平均実行時間が最も長いクエリのリスト
SELECT query, calls, total_time, rows, mean_time, stddev_time, min_time, max_time FROM pg_stat_statements ORDER BY mean_time DESC LIMIT 10;
- エラーが発生したクエリのリスト
SELECT query, calls, total_time, rows, mean_time, stddev_time, min_time, max_time, calls - rows AS error_count FROM pg_stat_statements WHERE calls > rows ORDER BY error_count DESC LIMIT 10;
pg_stat_activity
ビュー
pg_stat_activity
ビューは、現在のデータベース接続に関する情報を提供します。このビューを使用すると、現在実行中のクエリや待機状態を確認できます。
サンプルクエリ
- 現在実行中のクエリをリストする
SELECT pid, usename, application_name, client_addr, state, query, query_start FROM pg_stat_activity WHERE state = 'active';
- 特定のユーザーが実行中のクエリをリストする
SELECT pid, usename, application_name, client_addr, state, query, query_start FROM pg_stat_activity WHERE state = 'active' AND usename = 'your_username';
- 待機中のクエリをリストする
SELECT pid, usename, application_name, client_addr, state, wait_event_type, wait_event, query, query_start FROM pg_stat_activity WHERE wait_event IS NOT NULL;
- 長時間実行中のクエリをリストする
SELECT pid, usename, application_name, client_addr, state, query, query_start, now() - query_start AS duration FROM pg_stat_activity WHERE state = 'active' ORDER BY duration DESC LIMIT 10;
PostgreSQLのshared_buffers
設定は、サーバーの物理メモリに依存します。一般的なベストプラクティスとして、サーバーの物理メモリの25%〜40%をshared_buffers
に割り当てることが推奨されます。これを踏まえて、128GBおよび256GBのメモリがあるサーバーの場合のベストプラクティスを以下に示します。
128GBのメモリがあるサーバーの場合
shared_buffersの設定
- 推奨値: 32GB〜51.2GB
- 例:postgresqlコードをコピーする
shared_buffers = 32GB
256GBのメモリがあるサーバーの場合
shared_buffersの設定
- 推奨値: 64GB〜102.4GB
- 例:postgresqlコードをコピーする
shared_buffers = 64GB
理由と補足
- メモリの25%〜40%:
- この範囲は、PostgreSQLが効率的にデータをキャッシュし、ディスクI/Oを減らすために十分なメモリを提供します。メモリが多すぎると、オペレーティングシステム(OS)が利用するキャッシュと競合する可能性があるため、OSも適切にキャッシュを管理できるように残りのメモリを確保する必要があります。
- メモリの使い方のバランス:
shared_buffers
を増やすと、PostgreSQLがディスクI/Oを減らし、パフォーマンスを向上させることができますが、OSのキャッシュも重要です。OSはPostgreSQLのプロセスとは独立してキャッシュを管理し、ディスクアクセスの効率を上げます。
その他の設定の調整
shared_buffers
の設定を変更した場合、他の設定も調整する必要があります。以下は、それに関連する設定の例です。
work_mem
- 推奨値: クエリごとに使用される一時メモリのサイズを設定。並行クエリの数に応じて調整。
- 例:
work_mem = 64MB -- 大規模なクエリや分析処理に応じて調整
maintenance_work_mem
- 推奨値: 1GB〜4GB
- 例:
maintenance_work_mem = 2GB
effective_cache_size
- 推奨値: サーバーの物理メモリの50%〜75%
- 例:
effective_cache_size = 96GB -- 128GBメモリのサーバーの場合 effective_cache_size = 192GB -- 256GBメモリのサーバーの場合
具体的な設定例
128GBのメモリの場合
shared_buffers = 32GB
work_mem = 64MB
maintenance_work_mem = 2GB
effective_cache_size = 96GB
256GBのメモリの場合
shared_buffers = 64GB
work_mem = 64MB
maintenance_work_mem = 2GB
effective_cache_size = 192GB
複合インデックスは、複数の列に対するインデックスを1つにまとめたものです。複合インデックスを適切に設計することで、複数のクエリを効率的にカバーでき、クエリパフォーマンスを向上させることができます。以下に、複合インデックスの利点や使用方法、設計時の注意点について詳しく説明します。
複合インデックスの利点
- クエリのパフォーマンス向上:
- 複合インデックスを使用することで、特定のクエリが複数の単一列インデックスを使用するよりも効率的に実行される場合があります。
- インデックスの重複を避ける:
- 単一列インデックスを複数設定するよりも、複合インデックスを1つ設定することで、インデックスの重複を避け、ストレージ使用量を削減できます。
- 特定のクエリパターンを効率化:
- 複合インデックスは、複数の列に基づく検索やソートを効率化するために有用です。
使用方法
以下に、複合インデックスの作成方法とその効果を説明します。
例1: 単一列インデックスの使用例
テーブル orders
に以下のクエリが頻繁に実行されるとします。
SELECT * FROM orders WHERE customer_id = ?;
SELECT * FROM orders WHERE product_id = ?;
この場合、以下の単一列インデックスを作成することが一般的です。
CREATE INDEX idx_customer_id ON orders(customer_id);
CREATE INDEX idx_product_id ON orders(product_id);
例2: 複合インデックスの使用例
上記のクエリに加えて、以下のクエリも頻繁に実行されるとします。
SELECT * FROM orders WHERE customer_id = ? AND product_id = ?;
この場合、複合インデックスを使用することでクエリパフォーマンスを向上させることができます。
CREATE INDEX idx_customer_product ON orders(customer_id, product_id);
この複合インデックスは、以下のクエリをカバーします。
SELECT * FROM orders WHERE customer_id = ?;
SELECT * FROM orders WHERE customer_id = ? AND product_id = ?;
複合インデックス設計時の注意点
- 列の順序:
- 複合インデックス内の列の順序は重要です。インデックスは先頭の列から順に最適化されるため、最も選択度の高い(すなわち、クエリのフィルタリングに最も寄与する)列を最初に配置することが推奨されます。
- 部分的なカバー:
- 複合インデックスは、インデックスの先頭部分の列に基づくクエリにも効果的です。例えば、
CREATE INDEX idx_customer_product ON orders(customer_id, product_id);
はcustomer_id
のみに基づくクエリもカバーしますが、product_id
のみに基づくクエリはカバーしません。
- 複合インデックスは、インデックスの先頭部分の列に基づくクエリにも効果的です。例えば、
- インデックスサイズ:
- 複合インデックスは、単一列インデックスよりもサイズが大きくなる傾向があります。テーブルの列数やデータの規模に応じて、インデックスサイズがストレージに与える影響を考慮する必要があります。
具体例の解説
以下に、具体例を挙げて説明します。
テーブル定義
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT,
product_id INT,
order_date DATE,
amount DECIMAL
);
クエリパターン
SELECT * FROM orders WHERE customer_id = 123;
SELECT * FROM orders WHERE product_id = 456;
SELECT * FROM orders WHERE customer_id = 123 AND product_id = 456;
この場合、複数の単一列インデックスを作成する代わりに、以下のような複合インデックスを作成します。
複合インデックスの作成
CREATE INDEX idx_customer_product ON orders(customer_id, product_id);
クエリの最適化
SELECT * FROM orders WHERE customer_id = 123;
:- このクエリは、
idx_customer_product
インデックスを使用して効率的に実行されます。
- このクエリは、
SELECT * FROM orders WHERE product_id = 456;
:- このクエリは、
idx_customer_product
インデックスを使用しません。この場合、別途product_id
に対する単一列インデックスを作成する必要があります。
- このクエリは、
SELECT * FROM orders WHERE customer_id = 123 AND product_id = 456;
:- このクエリは、
idx_customer_product
インデックスを使用して効率的に実行されます。
- このクエリは、
複合インデックスが特定の列のみに対するクエリに対して効果を発揮しない理由を理解するためには、インデックスの内部構造とPostgreSQLがどのようにインデックスを利用するかを理解する必要があります。
インデックスの内部構造
インデックスはツリー構造(通常はB-tree)で実装されており、列の値に基づいてデータを効率的に検索できるようになっています。複合インデックスの場合、インデックスは複数の列を組み合わせたキーを持つ形で構築されます。例えば、CREATE INDEX idx_customer_product ON orders(customer_id, product_id);
というインデックスは、以下のようなキーの順序で構成されます。
(customer_id, product_id)
インデックスが利かない理由
プレフィックス(先頭部分)ルール
複合インデックスが有効に使われるには、クエリの検索条件がインデックスの先頭部分(プレフィックス)に一致している必要があります。具体的には、以下の条件が必要です。
- インデックスの先頭部分に一致する検索条件が含まれている。
- 検索条件がインデックスの列の順序に従っている。
例
インデックスが (customer_id, product_id)
で構成されている場合、以下のクエリはインデックスを利用できます。
SELECT * FROM orders WHERE customer_id = 123;
– 先頭のcustomer_id
に一致SELECT * FROM orders WHERE customer_id = 123 AND product_id = 456;
– インデックス全体に一致
しかし、以下のクエリはインデックスを利用できません。
SELECT * FROM orders WHERE product_id = 456;
– インデックスの先頭部分に一致しない
インデックスのスキャン順序
インデックスのツリー構造は、最初のキー(この場合は customer_id
)に基づいて並べられており、その次に2番目のキー(この場合は product_id
)が続きます。したがって、product_id
の値だけを使ってツリー構造を効果的にスキャンすることはできません。具体的には、customer_id
がどのような値であっても、その下にあるproduct_id
の特定の値を見つけることができるように、ツリー全体をスキャンする必要があるため、効率的ではありません。
回避策
個別インデックスの追加
product_id
のみに対するクエリを頻繁に行う場合は、別途product_id
に対するインデックスを作成するのが一般的です。
CREATE INDEX idx_product_id ON orders(product_id);
これにより、以下のクエリは新しいインデックスを利用して効率的に実行されます。
SELECT * FROM orders WHERE product_id = 456;
マルチカラムインデックスの利用
場合によっては、複合インデックスの順序を変更することも検討できます。ただし、この場合はcustomer_id
とproduct_id
の組み合わせを含むクエリの頻度と性能を考慮する必要があります。
sqlコードをコピーするCREATE INDEX idx_product_customer ON orders(product_id, customer_id);
このインデックスは以下のクエリに対して有効です。
SELECT * FROM orders WHERE product_id = 456;
SELECT * FROM orders WHERE product_id = 456 AND customer_id = 123;
ただし、customer_id
のみに基づくクエリには効果がありません。
内部結合(INNER JOIN)と外部結合(LEFT JOIN、RIGHT JOIN)を行う場合のインデックス設計について説明します。以下に、例として3つのテーブルを使用し、結合クエリに対するインデックス設計の方法を具体的に示します。
例: 3つのテーブル
以下の3つのテーブルを使用します。
customers
テーブルorders
テーブルproducts
テーブル
CREATE TABLE customers (
customer_id SERIAL PRIMARY KEY,
customer_name VARCHAR(255) NOT NULL
);
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT NOT NULL,
order_date DATE NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id),
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
CREATE TABLE products (
product_id SERIAL PRIMARY KEY,
product_name VARCHAR(255) NOT NULL,
price DECIMAL NOT NULL
);
結合クエリの例
- 内部結合クエリ(INNER JOIN)
- 左外部結合クエリ(LEFT JOIN)
1. 内部結合クエリ(INNER JOIN)
以下のクエリは、customers
、orders
、products
のデータを内部結合して取得します。
SELECT
c.customer_name,
o.order_id,
o.order_date,
p.product_name,
o.quantity
FROM
orders o
INNER JOIN
customers c ON o.customer_id = c.customer_id
INNER JOIN
products p ON o.product_id = p.product_id
WHERE
c.customer_name = 'John Doe'
AND p.product_name = 'Product A';
2. 左外部結合クエリ(LEFT JOIN)
以下のクエリは、customers
テーブルの全ての行と、対応する注文および製品のデータを左外部結合して取得します。
SELECT
c.customer_name,
o.order_id,
o.order_date,
p.product_name,
o.quantity
FROM
customers c
LEFT JOIN
orders o ON c.customer_id = o.customer_id
LEFT JOIN
products p ON o.product_id = p.product_id
WHERE
c.customer_name = 'John Doe';
インデックス設計
これらのクエリを効率的に実行するためのインデックス設計を行います。
1. 内部結合クエリのインデックス設計
customers
テーブルのcustomer_name
列にインデックスを作成します。orders
テーブルのcustomer_id
列にインデックスを作成します(この列は外部キーです)。products
テーブルのproduct_name
列にインデックスを作成します。orders
テーブルのproduct_id
列にインデックスを作成します(この列は外部キーです)。
CREATE INDEX idx_customers_customer_name ON customers(customer_name);
CREATE INDEX idx_orders_customer_id ON orders(customer_id);
CREATE INDEX idx_products_product_name ON products(product_name);
CREATE INDEX idx_orders_product_id ON orders(product_id);
2. 左外部結合クエリのインデックス設計
- 内部結合クエリと同様のインデックスを作成します。左外部結合クエリでも同様のインデックスが効果的です。
CREATE INDEX idx_customers_customer_name ON customers(customer_name);
CREATE INDEX idx_orders_customer_id ON orders(customer_id);
CREATE INDEX idx_products_product_name ON products(product_name);
CREATE INDEX idx_orders_product_id ON orders(product_id);
結合クエリの最適化ポイント
- 結合キーにインデックスを設定:
- 結合に使用されるキー(
customer_id
、product_id
)にインデックスを設定することで、結合操作の効率が向上します。
- 結合に使用されるキー(
- フィルタ条件にインデックスを設定:
- フィルタ条件(
customer_name
、product_name
)にインデックスを設定することで、クエリのフィルタリングが効率化されます。
- フィルタ条件(
- クエリプランの確認:
EXPLAIN
およびEXPLAIN ANALYZE
を使用して、クエリの実行計画を確認し、インデックスが適切に使用されているかを確認します。
EXPLAIN ANALYZE
SELECT
c.customer_name,
o.order_id,
o.order_date,
p.product_name,
o.quantity
FROM
orders o
INNER JOIN
customers c ON o.customer_id = c.customer_id
INNER JOIN
products p ON o.product_id = p.product_id
WHERE
c.customer_name = 'John Doe'
AND p.product_name = 'Product A';
まとめ
結合クエリを効率的に実行するためには、以下のポイントを考慮してインデックス設計を行うことが重要です。
- 結合キーにインデックスを設定することで、結合操作の効率を向上させる。
- フィルタ条件にインデックスを設定することで、クエリのフィルタリングを効率化する。
- クエリプランを確認し、インデックスが適切に使用されているかを確認する。
これらの設計ポイントを押さえることで、複数テーブルの結合クエリを効率的に実行し、パフォーマンスを最適化することができます。
この場合:
- Planning Time: 0.100 ms
- クエリの解析、再帰的分解、および最適な実行計画の決定に0.100ミリ秒かかっています。
- Execution Time: 0.070 ms
- 実際にデータベースからデータを取得し、結果セットを生成するのに0.070ミリ秒かかっています。
これらの時間の重要性
- Planning Time が長い場合:
- 複雑なクエリや結合が多い場合、または統計情報が不足している場合に計画段階が時間がかかることがあります。頻繁に実行されるクエリであれば、計画段階を短縮するための対策(例:プリペアドステートメントの利用)が考慮されるべきです。
- Execution Time が長い場合:
- 大量のデータ処理や非効率な実行計画(例えばシーケンシャルスキャン)が原因で、実行時間が長くなることがあります。この場合、インデックスの追加やクエリの最適化が必要です。
まとめ
Planning Time
と Execution Time
はクエリの異なる段階でかかる時間を示しており、どちらもクエリパフォーマンスを最適化するための重要な指標です。これらの時間を詳細に分析することで、クエリのどの部分がボトルネックとなっているかを特定し、適切な最適化手法を講じることができます。
Materialize
目的
Materialize
ノードは、サブクエリの結果やテーブル関数の結果など、再利用される中間結果をメモリに一時的に保存するために使用されます。これにより、同じサブクエリが複数回実行される場合に、その計算結果をキャッシュし、再計算を防ぐことができます。
動作
Materialize
は中間結果をメモリに保存し、後続のノードがそのデータを繰り返し使用する際に効率的にアクセスできるようにします。典型的には、ネストされたループ結合の内側のサブクエリや、ウィンドウ関数の結果などが対象となります。
Memoize
目的
Memoize
ノードは、再帰的なクエリやサブクエリの結果をキャッシュして、同じ入力に対して同じ出力を返すことを目的とします。これにより、同じ計算を何度も繰り返すことを避け、クエリのパフォーマンスを向上させることができます。
動作
Memoize
は、入力パラメータの組み合わせに対する計算結果をキャッシュに保持します。同じパラメータが再度現れた場合は、キャッシュされた結果を返します。これにより、特に再帰クエリでのパフォーマンスが向上します。