Chào các bạn.
Nhân tiện có bạn hỏi về REINDEX nên mình viết bài này để giải thích thêm về REINDEX và VACUUM FULL, khi nào phải thực hiện các thao tác này và cần chú ý những gì khi sử dụng chức năng này. Trong bài viết về VACUUM, mình có giải thích về chức năng và các xử lý mà VACUUM thực hiện. But chưa nói về 2 chức năng liên quan này.
Trước khi bắt đầu giải thích về VACUUM FULL và REINDEX, mình xin trả lời trước một số nghi vấn mà lúc tiếp xúc với PostgreSQL các bạn hay gặp phải.
Câu trả lời là có. VACUUM lấy lại dữ liệu phân mảnh cho table và những index tương ứng của table đó.
But không giống với table, index không có Visibility Map(VM) nên VACUUM thực hiện scan toàn bộ file index tốn nhiều disk I/O để tìm kiếm và thực hiện lấy lại dữ liệu dư thừa. Đây cũng là một điểm bất lợi về performance của VACUUM.
Lý do chính trong vận hành khi thực hiện 2 chức năng này là để khắc phục tình trạng file dữ liệu (table hay index) bị tăng quá lớn.
Hai chức năng này khi chạy sẽ ảnh hưởng nhiều tới hệ thống. Bạn nên tham khảo kỹ chú ý ở cuối bài viết này rồi thực hiện cho đúng.
Như trong bài viết về VACUUM mình đã nói qua, PostgreSQL sử dụng cơ chế không xóa dữ liệu vật lý ngay mà chỉ đánh dấu đã xóa để thực hiện chức năng MVCC. Những dữ liệu bị đánh dấu đã xóa (dữ liệu bị phân mảnh) này, không được giải phóng ngay cả khi transaction đã COMMIT. Một trong những chức năng của VACUUM (autovacuum) là lấy lại những dữ liệu bị phân mảnh này để tái sử dụng.
Như như hình vẽ minh họa bên dưới, dữ liệu dư thừa được lấy về để tái sử dụng khi VACUUM được thực thi đúng cách. But nếu block dữ liệu hữu hiệu nằm ở cuối file thì kích thước file không được giảm.
Vấn đề trên làm cho dung lượng dư thừa không được trả về cho hệ thống. Ngoài ra nếu file dữ liệu lớn việc tìm seek dữ liệu trên đĩa cứng cũng ảnh hưởng tới performance.
postgres=# create table testtbl as select generate_series(1,100000) as id, random()::text as c1; SELECT 100000 postgres=# create index test_idx on testtbl using btree (id); CREATE INDEX postgres=# analyze testtbl; ANALYZE postgres=# select pg_relation_size('testtbl'); pg_relation_size ------------------ 5226496 (1 row) postgres=# select pg_relation_size('test_idx'); pg_relation_size ------------------ 2260992 (1 row)
Ở đây mình sử dụng thêm contrib pgstattuple để kiểm tra độ phân mảnh của table và index.
postgres=# delete from testtbl where id < 99999; DELETE 99998 postgres=# analyze testtbl; ANALYZE postgres=# select dead_tuple_percent,free_space from pgstattuple('testtbl'); dead_tuple_percent | free_space --------------------+------------ 88 | 7904 (1 row) postgres=# select avg_leaf_density,leaf_pages from pgstatindex('test_idx'); avg_leaf_density | leaf_pages ------------------+------------ 89.83 | 274 (1 row)
postgres=# vacuum testtbl; VACUUM postgres=# select pg_relation_size('testtbl'); pg_relation_size ------------------ 5226496 (1 row) postgres=# select pg_relation_size('test_idx'); pg_relation_size ------------------ 2260992 (1 row) postgres=# select dead_tuple_percent,free_space from pgstattuple('testtbl'); dead_tuple_percent | free_space --------------------+------------ 0 | 4808536 (1 row) postgres=# select avg_leaf_density,leaf_pages from pgstatindex('test_idx'); avg_leaf_density | leaf_pages ------------------+------------ 0.54 | 1 (1 row)
postgres=# insert into testtbl select generate_series(1,2000),random()::text; INSERT 0 2000 postgres=# analyze testtbl; ANALYZE postgres=# select pg_relation_size('testtbl'); pg_relation_size ------------------ 5226496 (1 row) postgres=# select pg_relation_size('test_idx'); pg_relation_size ------------------ 2301952 (1 row) postgres=# select dead_tuple_percent,free_space from pgstattuple('testtbl'); dead_tuple_percent | free_space --------------------+------------ 0 | 4712512 (1 row) postgres=# select avg_leaf_density,leaf_pages from pgstatindex('test_idx'); avg_leaf_density | leaf_pages ------------------+------------ 82.11 | 6 (1 row)
postgres=# vacuum full testtbl; VACUUM postgres=# select pg_relation_size('testtbl'); pg_relation_size ------------------ 106496 (1 row) postgres=# select pg_relation_size('test_idx'); pg_relation_size ------------------ 65536 (1 row) postgres=# select dead_tuple_percent,free_space from pgstattuple('testtbl'); dead_tuple_percent | free_space --------------------+------------ 0 | 2012 (1 row) postgres=# select avg_leaf_density,leaf_pages from pgstatindex('test_idx'); avg_leaf_density | leaf_pages ------------------+------------ 82.11 | 6 (1 row)
postgres=# truncate testtbl; TRUNCATE TABLE postgres=# insert into testtbl select generate_series(1,100000), random()::text; INSERT 0 100000
postgres=# delete from testtbl where id < 99999; DELETE 99998 postgres=# analyze testtbl; ANALYZE postgres=# select pg_relation_size('testtbl'); pg_relation_size ------------------ 5226496 (1 row) postgres=# select pg_relation_size('test_idx'); pg_relation_size ------------------ 2260992 (1 row)
postgres=# reindex index test_idx; REINDEX postgres=# select pg_relation_size('testtbl'); pg_relation_size ------------------ 5226496 (1 row) postgres=# select pg_relation_size('test_idx'); pg_relation_size ------------------ 16384 (1 row) postgres=#
Là chức năng tạo lại file index. Thực tế, chức năng này thường được sử dụng trong những trường hợp bên dưới.
REINDEX có thể thực hiện bằng lệnh SQL REINDEX hoặc câu lệnh binary reindexdb. Tùy vào cú pháp mà ta có thể thay đổi phạm vi thực hiện REINDEX.
postgres=# \h reindex Command: REINDEX Description: rebuild indexes Syntax: REINDEX [ ( VERBOSE ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } name
$ reindexdb --help
reindexdb reindexes a PostgreSQL database.
Usage:
reindexdb [OPTION]... [DBNAME]
Options:
-a, --all reindex all databases
-d, --dbname=DBNAME database to reindex
-e, --echo show the commands being sent to the server
-i, --index=INDEX recreate specific index(es) only
-q, --quiet don't write any messages
-s, --system reindex system catalogs
-S, --schema=SCHEMA reindex specific schema(s) only
-t, --table=TABLE reindex specific table(s) only
-v, --verbose write a lot of output
-V, --version output version information, then exit
-?, --help show this help, then exit
... còn nữa
Là một chức năng của VACUUM. Ngoài chức năng VACUUM thông thường, VACUUM FULL thực hiện tạo lại file table và những index liên quan tới table tương ứng đó.
VACUUM FULL có thể thực hiện bằng lệnh SQL hoặc câu lệnh binary vacuumdb -f. Tùy vào cú pháp mà ta có thể thay đổi phạm vi thực hiện VACUUM FULL.
postgres=# \h vacuum Command: VACUUM Description: garbage-collect and optionally analyze a database Syntax: VACUUM [ ( { FULL | FREEZE | VERBOSE | ANALYZE | DISABLE_PAGE_SKIPPING } [, ...] ) ] [ table_name [ (column_name [, ...] ) ] ] VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ table_name ] VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] ANALYZE [ table_name [ (column_name [, ...] ) ] ] postgres=#
$ vacuumdb --help
vacuumdb cleans and analyzes a PostgreSQL database.
Usage:
vacuumdb [OPTION]... [DBNAME]
Options:
-a, --all vacuum all databases
-d, --dbname=DBNAME database to vacuum
-e, --echo show the commands being sent to the server
-f, --full do full vacuuming
-F, --freeze freeze row transaction information
-j, --jobs=NUM use this many concurrent connections to vacuum
-q, --quiet don't write any messages
-t, --table='TABLE[(COLUMNS)]' vacuum specific table(s) only
-v, --verbose write a lot of output
-V, --version output version information, then exit
-z, --analyze update optimizer statistics
-Z, --analyze-only only update optimizer statistics; no vacuum
--analyze-in-stages only update optimizer statistics, in multiple
stages for faster results; no vacuum
... còn nữa
REINDEX và VACUUM FULL có những chú ý như bên dưới. Bạn nên tham khảo kỹ trước khi sử dụng để hệ thống/service của bạn chịu ảnh hưởng ít nhất.
Thông thường, trường hợp vận hành lâu ngày table files và index files trở nên lớn khác thường so với lượng record hiện tại ta mới sử dụng VACUUM FULL.
Facebook Comments Box