ON DELETE CASCADE非常慢

时间:2013-06-21 18:03:13

标签: performance postgresql types indexing

我正在使用Postgres 8.4。我的系统配置是窗口7 32位4 gb ram和2.5ghz。

我在Postgres有一个数据库,有10个表t1, t2, t3, t4, t5.....t10

t1的主键是序列ID,它是对所有其他表的外键引用。

数据插入数据库(即所有表中)除了t1之外,所有其他表都有近50,000行数据但t1有一行,其主键是从所有其他表引用的。然后我在t1中插入第二行数据,并在其他表中再插入50,000行这个新引用。

问题是当我想删除其他表中存在的所有数据条目时:

delete from t1 where column1='1'

此查询需要将近10分钟才能执行。

我也创建了索引并尝试过,但性能并没有提高。 可以做些什么?

我在下面提到了一个示例模式

CREATE TABLE t1
(
  c1 numeric(9,0) NOT NULL,
  c2 character varying(256) NOT NULL,
  c3ver numeric(4,0) NOT NULL,
  dmlastupdatedate timestamp with time zone NOT NULL,
  CONSTRAINT t1_pkey PRIMARY KEY (c1),
  CONSTRAINT t1_c1_c2_key UNIQUE (c2)
);

CREATE TABLE t2
(
  c1 character varying(100),
  c2 character varying(100),
  c3 numeric(9,0) NOT NULL,
  c4 numeric(9,0) NOT NULL,
  tver numeric(4,0) NOT NULL,
  dmlastupdatedate timestamp with time zone NOT NULL,
  CONSTRAINT t2_pkey PRIMARY KEY (c3),
  CONSTRAINT t2_fk FOREIGN KEY (c4)
      REFERENCES t1 (c1) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE CASCADE,
  CONSTRAINT t2_c3_c4_key UNIQUE (c3, c4)
);

CREATE INDEX t2_index ON t2 USING btree (c4);

让我知道架构是否有任何问题。

1 个答案:

答案 0 :(得分:1)

对于更大的表和超过两个或三个值,您需要在引用列(t1.c1)上引用索引以及引用列(t2.c4,...)。

但是,如果您的描述准确无误,可能会导致您的方案中出现性能问题。由于t1中只有 2 不同的值,因此索引没有用处。顺序扫描会更快。

无论如何,我重新制定了你在Postgres 9.1.9中描述的内容

CREATE TABLE t1
( c1 numeric(9,0) PRIMARY KEY,
  c2 character varying(256) NOT NULL,
  c3ver numeric(4,0) NOT NULL,
  dmlastupdatedate timestamptz NOT NULL,
  CONSTRAINT t1_uni_key UNIQUE (c2)
);

CREATE temp TABLE t2
( c1 character varying(100),
  c2 character varying(100),
  c3 numeric(9,0) PRIMARY KEY,
  c4 numeric(9,0) NOT NULL,
  tver numeric(4,0) NOT NULL,
  dmlastupdatedate timestamptz NOT NULL,
  CONSTRAINT t2_uni_key UNIQUE (c3, c4),
  CONSTRAINT t2_c4_fk FOREIGN KEY (c4)
      REFERENCES t1(c1) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE CASCADE
);

INSERT INTO t1 VALUES 
 (1,'OZGPIGp7tgp97tßp97tß97tgP?)/GP)7gf', 234, now())
,(2,'agdsOZGPIGp7tgp97tßp97tß97tgP?)/GP)7gf', 4564, now());

INSERT INTO t2
SELECT'shOahaZGPIGp7tgp97tßp97tß97tgP?)/GP)7gf'
     ,'shOahaZGPIGp7tgp97tßp97tß97tgP?)/GP)7gf'
     , g, 2, 456, now()
from generate_series (1,50000) g

INSERT INTO t2
SELECT'shOahaZGPIGp7tgp97tßp97tß97tgP?)/GP)7gf'
     ,'shOahaZGPIGp7tgp97tßp97tß97tgP?)/GP)7gf'
     , g, 2, 789, now()
from generate_series (50001, 100000) g

ANALYZE t1;
ANALYZE t2;

EXPLAIN ANALYZE DELETE FROM t1 WHERE c1 = 1;

总运行时间:53.745毫秒

DELETE FROM t1 WHERE c1 = 1;

执行时间为58毫秒。

问题,您的架构布局没有根本性的错误

次要增强功能:

  • 您定义了几列numeric(9,0)numeric(4,0)。除非你有充分的理由这样做,否则只使用 integer 可能会好得多。它们整体更小更快。如果确实需要强制执行最大值,则可以随时添加检查约束。

  • 我也会use text instead of varchar(n)

  • 重新排序列(在创建表时)。根据经验,首先放置固定长度的NOT NULL列。首先放置timestampinteger,最后放置numerictextMore here.