Amazon RDS(2vCPU、8 GB RAM)でPostgres 9.5を使用しています。
私はpganalyzeを使用して自分のパフォーマンスを監視しています。
データベースに約200Kのレコードがあります。
私のダッシュボードでは、次のクエリの実行に平均28秒と11秒かかっています。
UPDATE calls SET ... WHERE calls.uuid = ? telephonist 28035.41 0.01 100% 0.03%
UPDATE calls SET sip_error = ? WHERE calls.uuid = ? telephonist 11629.89 0.44 100% 0.69%
私はすでにVACUUM
を試し、7,670の死んだ行を見つけて削除しました。UPDATE
のパフォーマンスを向上させる方法はありますか?これはクエリです:
UPDATE calls SET X=Y WHERE calls.uuid = 'Z'
上記のクエリをどのように改善できますか?別のフィールドを追加できますか?例:
UPDATE calls SET X=Y WHERE calls.uuid = 'Z' AND calls.campaign = 'W'
列uuid
はインデックス付けされていません。
https://www.tutorialspoint.com/postgresql/postgresql_indexes.htm は、UPDATE
操作にはインデックスを推奨しないことを示唆しています。
CREATE TABLE public.calls (
id int4 NOT NULL DEFAULT nextval('calls_id_seq'::regclass),
callsid varchar(128),
call_start timestamp(6) NOT NULL,
call_end timestamp(6) NULL,
result int4 DEFAULT 0,
destination varchar(256),
campaign varchar(128),
request_data varchar(4096),
uuid varchar(128) NOT NULL,
status varchar(64),
duration int4,
recording_file varchar(256),
recording_url varchar(256),
recording_duration int4,
recording_text varchar(4096),
recording_download bool DEFAULT false,
description varchar(4096),
analysis varchar(4096),
is_fax bool DEFAULT false,
is_test bool,
hangup_cause varchar(128),
media_detected bool DEFAULT false,
sip_callid varchar(256),
hangup_cause_override varchar(256),
is_blacklisted bool DEFAULT false,
sip_error varchar(256),
hangup_cause_report varchar(128),
summary varchar(1024)
);
EXPLAIN ANALYZE
SELECT * FROM calls
WHERE calls.uuid='e2ce9eb4-v1lp-p14u-7kkk-lruy-e2ceaae46d';
コールのシーケンススキャン(コスト= 0.00..16716.25行= 1幅= 3301) (実際の時間= 81.637..81.637行= 0ループ= 1) フィルター: ((uuid):: text = 'e2ce9eb4-v1lp-p14u-7kkk-lruy-e2ceaae46d' :: text) フィルターによって削除された行:99970 計画時間:0.482 ms 実行時間:81.683ミリ秒
仮定列uuid
はUNIQUE
であると想定されています。このテーブル定義は、スペースを節約し、パフォーマンスを向上させるはずです。
CREATE TABLE public.calls (
id serial PRIMARY KEY,
result int4 DEFAULT 0 NOT NULL,
uuid uuid UNIQUE NOT NULL -- creates the index you need automatically
call_start timestamp NOT NULL,
call_end timestamp, -- so this can be NULL?
duration int4,
recording_duration int4,
callsid varchar(128),
destination varchar(256),
campaign varchar(128),
request_data varchar(4096),
status varchar(64),
recording_file varchar(256),
recording_url varchar(256),
recording_text varchar(4096),
recording_download bool DEFAULT false,
description varchar(4096),
analysis varchar(4096),
is_fax bool DEFAULT false,
is_test bool,
hangup_cause varchar(128),
media_detected bool DEFAULT false,
sip_callid varchar(256),
hangup_cause_override varchar(256),
is_blacklisted bool DEFAULT false,
sip_error varchar(256),
hangup_cause_report varchar(128),
summary varchar(1024)
);
ここで最も重要な機能はUNIQUE
制約です。これは一意のindexで実装されており、インデックスは必要以上のものですその他( @ ypercubeはコメント済み など)。
uuid
が一意でない場合は、プレーンなbtreeインデックスを作成します。
uuid
が有効なuuidでない場合は、文字タイプ(varchar
またはtext
)のままにしますが、そのインデックスを作成します。
データ型varchar
とuuid
のサイズとパフォーマンスに関する考慮事項:
私の他の提案された変更はすべてマイナーな改善です。詳細な説明はこちら:
特定の最大長を強制する必要がない場合は、すべての文字列にtext
を使用します。ただし、それがパフォーマンスに直接影響することはほとんどありません。一部の列は、より適切なタイプに変換される場合があります(実際のパフォーマンス上の利点があります)。
UPDATE
では、なぜ そのチュートリアルページ と言うのですか。
いつインデックスを回避すべきですか?
[...]
-頻繁な大規模なバッチ更新または挿入操作があるテーブル。
それは省略によって誤解を招くものです。あなた必死に更新の述語をサポートするには、uuid
に1つのインデックスが必要です。他のすべてのインデックスは、更新後にそれらを最新に保つために追加の作業を必要とするため、更新が遅くなります。したがって、PRIMARY KEY
on id
(たとえば、FK制約を許可するため)をドロップできます(代わりにuuid
をPKにする-自動的にインデックスが作成されます)。