提高大表的 UPDATE 性能

cal*_*ian 5 postgresql performance index-tuning update amazon-rds postgresql-performance

我在 Amazon RDS(2vCPU,8 GB RAM)上使用 Postgres 9.5。
我使用 pganalyze 来监控我的表现。
我在数据库中有大约 20 万条记录。

在我的仪表板中,我看到以下查询的平均执行时间为 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%
Run Code Online (Sandbox Code Playgroud)

我已经尝试VACUUM、发现并清理了 7,670 个死行。
任何想法如何提高UPDATE性能?这是查询:

UPDATE calls SET X=Y WHERE calls.uuid = 'Z'
Run Code Online (Sandbox Code Playgroud)

如何改进上述查询?我可以添加另一个字段吗?例子:

UPDATE calls SET X=Y WHERE calls.uuid = 'Z' AND calls.campaign = 'W'
Run Code Online (Sandbox Code Playgroud)

该列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)
);
Run Code Online (Sandbox Code Playgroud)
EXPLAIN ANALYZE 
    SELECT * FROM calls 
    WHERE calls.uuid='e2ce9eb4-v1lp-p14u-7kkk-lruy-e2ceaae46d';
Run Code Online (Sandbox Code Playgroud)
Seq Scan on call(成本=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 毫秒

Erw*_*ter 10

假设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)
);
Run Code Online (Sandbox Code Playgroud)

这里最重要的特性是UNIQUE约束,它是用唯一索引实现的,而索引是你最需要的(比如@ypercube 已经评论过)。

如果uuid不是唯一的,则在其上创建一个普通的 btree 索引。

如果uuid不是有效的 uuid,则将其保留为字符类型 (varchartext),但仍会创建该索引。

数据类型varchar与 的大小和性能注意事项uuid

我所有其他建议的更改都是小的改进。详细解释在这里:

如果您不需要强制执行特定的最大长度,我只会将其text用于所有字符列。但这对性能几乎没有任何直接影响。某些列可能会转换为更合适的类型(具有实际的性能优势)。


索引和 UPDATE

那么为什么那个教程页面会说:

什么时候应该避免索引?
[...]
- 具有频繁、大批量更新或插入操作的表。

这是疏忽的误导。您迫切需要一个索引uuid来支持更新的谓词。所有其他索引都会减慢您的更新速度,因为它们需要额外的工作才能在更新后保持最新状态。因此,如果您没有使用PRIMARY KEYon id(例如允许对其进行 FK 约束),您可以删除它(并uuid改为使用 PK - 也​​自动索引)。


归档时间:

查看次数:

16983 次

最近记录:

9 年,6 月 前