|
我有以下UPDATE查询:
) o/ p1 P3 [( l! ~. Y9 e- gUPDATE Indexer.Pages SET LastError=NULL where LastError is not null;
! X ^8 F+ p9 G# X目前,此查询大约需要93分钟才能完成。我想找到使它更快一点的方法。
' m( P5 P- V# c d% I8 g( F% ^+ g该Indexer.Pages表大约有506,000行,其中大约490,000行包含的值LastError,因此我怀疑我是否可以利用此处的任何索引。$ \0 b" Q; r4 q- T. h7 f2 Q! t
该表(未压缩时)中包含约46
9 ]7 P) X% [( u9 H% i3 [" k4 E$ mgigs的数据,但是该数据的大部分位于名为的文本字段中html。我相信简单地加载和卸载许多页面会导致速度下降。一个想法是做一个新表 只是
- Z& p$ y' S3 M3 P5 |; {0 w) j: |/ m在Id和html现场,并保持Indexer.Pages尽可能小。但是,测试该理论将是一件可观的工作,因为我实际上没有硬盘空间来创建表的副本。我必须将其复制到另一台计算机上,放下表,然后将数据复制回去,这可能需要整个晚上。$ x! f) g, `- U5 E- f
有想法吗?我正在使用Postgres 9.0.0。5 y5 Q C+ A5 s: i: p
更新:& O: _& {5 B2 W& Z5 q' d; M
这是模式:
l: x7 O/ B: @8 U& v/ n: n6 \CREATE TABLE indexer.pages5 B, a' ?6 f6 o. k0 C
(
7 O" h: y% r0 I2 P$ a id uuid NOT NULL,
. V( h5 H [" ]$ |0 Y3 G& I url character varying(1024) NOT NULL,
' J ?6 M, ]% |- Z( y3 ^ firstcrawled timestamp with time zone NOT NULL,5 B7 N/ E! b8 ]4 g
lastcrawled timestamp with time zone NOT NULL,
' b. ]- U! d+ O) k: J0 k& C recipeid uuid,1 P$ P- {# K, Q5 S2 i6 t
html text NOT NULL,
- t- ?3 [3 j8 q4 b. ] lasterror character varying(1024),5 Z/ U1 I4 z! h
missingings smallint,2 W) o0 ?, l/ B2 ^5 j: K9 ]
CONSTRAINT pages_pkey PRIMARY KEY (id ),
6 R1 P3 R6 r6 k0 L CONSTRAINT indexer_pages_uniqueurl UNIQUE (url )" u1 V; S, d5 a6 a8 W$ u
);6 g3 l& r% C5 R8 j+ G% S& S* z
我也有两个索引:
6 T. m3 s3 ~) N2 ECREATE INDEX idx_indexer_pages_missingings
, ~1 V6 M4 Q3 \ d4 [ ON indexer.pages6 O, i/ }2 n* {$ j5 `' u/ y
USING btree
' ]4 T5 J6 }+ i$ V2 } (missingings )7 H; Z! b" C' e, u$ ?$ a
WHERE missingings > 0;* g: J0 F% o- y
和
) r o j$ z6 E! ^4 gCREATE INDEX idx_indexer_pages_null: J" l' v; h5 z6 x; v1 d
ON indexer.pages) I1 B9 d8 g6 c5 o4 @0 S$ D
USING btree, |5 A* g/ h6 s- r6 M8 ?* Z
(recipeid )
9 T4 W; [5 V; r1 D# m' ^+ R" i WHERE NULL::boolean;
) y" N5 V8 B; o J+ I: {/ }4 ?3 y该表上没有触发器,并且还有另一个表具有FK约束Pages.PageId。
' P$ D% N+ e% m% |: ~1 z- B2 s
: d6 G7 X0 D8 C4 I* f8 ]( s4 T4 v解决方案:* \; C0 Y( c# B% q, Q" ^! v
( m% _4 [' _0 b$ j$ h; ?
, J4 q4 {- m. Y
$ O8 p. o/ d# Z9 [) U/ ^ 在执行 其他任何操作 之前, 应将. T+ H; Q* L, [1 ^, Z( I
PostgreSQL 升级# X9 B. \& J. e" p! R! H
到当前版本,至少是主版本的最新安全版本。请参阅该项目的准则。8 r. x! p9 w. l; W2 o
我还想强调一下Kevin提到的涉及该列的 索引LastError。通常, HOT更新 可以回收数据页上的死行,并使UPDATE更快得多-
: C8 v% {1 X( Z% ?; E% ?2 E4 V* t8 |有效地消除了(大部分)清理工作的需要。9 i- v! |* E* Z' y9 q
如果您的列 以任何方式 在任何索引 中 使用,则会禁用HOT( r/ s4 w5 ^8 `7 i
UPDATE,因为它会破坏索引。如果真是这样,您应该可以通过在删除所有这些索引之前并稍后重新创建它们来大大加快查询 的 速度UPDATE。, @0 Q7 S! L. H
在这种情况下,它将有助于运行多个较小的UPDATE: 如果 ……
. e+ Q2 s" C% D$ Y2 `6 y, X! }update列不包含在任何索引中(启用HOT更新)。…UPDATE在 多个 \2 T1 b8 y+ p: D, y& a) A
事务中很容易分为多个补丁。…这些修补程序中的行分布在整个表上(物理上,而不是逻辑上)。…没有其他并发事务可以防止死元组被重用。
; T( d% w9 Y! ^! Y9 o( v- N$ i然后,您将不需要VACCUUM在多个修补程序之间进行操作,因为HOT更新可以直接重用死元组-仅重用来自 先前6 O$ g( h% s6 B- w5 v1 c0 v
事务的死元组,而不是来自相同或并发事务的元组。您可能想VACUUM在操作结束时安排一个时间,或者只是让自动真空完成其工作。
2 C0 Z3 b! K6 N# I1 a+ h" G7 ~对于UPDATE-不需要的任何其他索引,也可以执行相同操作,然后从您的数字判断,UPDATE无论如何都不会使用索引。如果要更新表的大部分内容,那么从头开始构建新索引要比对每个已更改的行进行增量更新索引要快得多。/ F0 G; O& O' @0 o/ u: ^
另外,您的更新不太可能破坏任何 外键约束
) d# }: m' X* q。您也可以尝试删除并重新创建它们。这确实会打开一个时隙,在该时隙中不会强制执行参照完整性。如果在此期间违反了完整性,则在UPDATE尝试重新创建FK时会收到错误消息。如果您在# O7 B( I1 A+ Q( n. H! ?# f6 ]
一个 事务中完成所有操作,则并发事务永远都不会看到已删除的FK,但是您要在表上进行写锁定-与删除/重新创建索引或触发器相同)/ R1 Q( n/ e3 u+ U; |$ n
最后,禁用和启用 ****更新不需要的
7 V/ K0 E: s0 M u/ x' \触发器 。3 ~( o2 j& q' }7 W+ d& J; n3 ~
确保一次完成所有这些操作。也许可以在许多较小的补丁程序中执行此操作,因此它不会阻塞并发操作太长时间。2 ^/ a# r }4 {) R7 x3 e- a; _& [
所以:+ ~* r- N4 b7 v* X5 a
BEGIN;; d: e6 W0 s! J* P
ALTER TABLE tbl DISABLE TRIGGER user; -- disable all self-made triggers0 f7 [5 W( u' M
-- DROP indexes (& fk constraints ?)
: @7 r# l* z% V" Q; }4 {2 Y! |-- UPDATE ...) S7 t% J) w' L7 k6 a3 k
-- RECREATE indexes (& fk constraints ?)
M5 Q V' a, b1 ?' tALTER TABLE tbl ENABLE TRIGGER user;, m" h% g# e2 S, ~# G
COMMIT;9 H) v, ]+ q0 M5 j9 K4 h
您不能VACUUM在事务块内运行。每个文档:
# i0 A0 P' w: c, t3 q& y. J- y [# d [( F7 d$ b6 a
VACUUM 无法在事务块内执行。* O, |$ N0 {) r3 p5 ]
* e0 |3 N( P A2 |4 U2 O您可以将您的操作分成几个大块,然后在两个之间运行: s7 t6 Q- t% r# v# A
VACUUM ANALYZE tbl;2 {0 M& o% f; g) S$ r7 F0 V3 @
如果您不必处理并发事务,则可以(甚至更有效): B4 Z8 |7 ]8 K2 N* d
ALTER TABLE tbl DISABLE TRIGGER user; -- disable all self-made triggers
( m& x5 Z2 G* g- }5 q2 s% t$ y-- DROP indexes (& fk constraints ?)/ r! o% A. L g% p& n
-- Multiple UPDATEs with logical slices of the table% ~( K) Q1 D* ^! u
-- each slice in its own transaction.& _! y# {* J+ r0 v- k4 j
-- VACUUM ANALYZE tbl; -- optionally in between, or autovacuum kicks in6 F/ B" h- y6 D# j, }9 ~
-- RECREATE indexes (& fk constraints ?)
6 y1 p+ a' X- J; `* LALTER TABLE tbl ENABLE TRIGGER user; |
|