ืืื ืื ืื ืกืื ืื ืื ืื ื ืขืื (ืขืืืก OLAP ืืืืื ืืจืื ืขื ืืกื ื ืชืื ืื OLTP) ืขืืืื ืงืืื? ืึตืื ื ืงื ืฉืืืื ืืืชืื ืืืืคื ืคืขืื ืืืงืฃ ืืฉืืืืชืืช ืืจืืืืช ืืื ืืืจืื ืขื ืืืจืคื?
ืคืชืืืช ืืืืจืคื
ืจืืฉืืช, ืืืื ื ืงืืข ืืื ืืืขืื ืฉืื ื ืจืืฆืื ืืคืชืืจ ืืืืฆื ืืื ืืืืื ืืืชืขืืจืจ.
ืืืจื ืืื ืืืฆื ืืื ืงืืจื ืขื ืฉืืืื ืงืื ืืืกืืช, ืืื ืฉืื ืื ืืชืจืืฉ ืืจืื ืฉืื ืืืื. ืืืจื ืืื ืื ืื ืืืจ ืืืจืื/ืืืจืืืื/ืืืจืืืื, ืฉืื UPDATE ืืืืฆืข ืืขืชืื ืงืจืืืืช, ืื ืชืืจ ืืืฅ ืืขืื ืืืืฉืื ืืจื ืืชืืฉื ืื ืืืื ืฉื ืืืจืืขืื, ืฉืืจืฉืืืืช ืฉืืื ืื ืืืื INSERT/DELETE.
ืืืื ื ื ืกื ืืฉืืืจ ืืช ืืืคืฉืจืืช ืขื ืืืจืืืื:
CREATE TABLE tbl(k text PRIMARY KEY, v integer);
CREATE INDEX ON tbl(v DESC); -- ะฟะพ ััะพะผั ะธะฝะดะตะบัั ะฑัะดะตะผ ัััะพะธัั ัะตะนัะธะฝะณ
INSERT INTO
tbl
SELECT
chr(ascii('a'::text) + i) k
, 0 v
FROM
generate_series(0, 25) i;
ืืืืงืืื, ืืงืฉืจ ืืืจ, ืืชืืืื ืืงืฉื ืืจืืื ืืืจืืื, ืืืกืคืช ืืื ืกืืืืกืืืงืืช ืืืจืืืืช, ืืื ืื ืืฉืคืืข ืขื ืืฉืืืื ืฉืื ื:
SELECT pg_sleep(10000);
ืืขืช ืื ื ืืขืืื ืื ืืช ืืขืจื ืฉื ืืื ืืืื ืื ืคืขืืื ืจืืืช. ืืืขื ืืืืจ ืื ืืกืื, ืืืื ื ืขืฉื ืืืช
DO $$
DECLARE
i integer;
tsb timestamp;
tse timestamp;
d double precision;
BEGIN
PERFORM dblink_connect('dbname=' || current_database() || ' port=' || current_setting('port'));
FOR i IN 1..10000 LOOP
tsb = clock_timestamp();
PERFORM dblink($e$UPDATE tbl SET v = v + 1 WHERE k = 'a';$e$);
tse = clock_timestamp();
IF i % 1000 = 0 THEN
d = (extract('epoch' from tse) - extract('epoch' from tsb)) * 1000;
RAISE NOTICE 'i = %, exectime = %', lpad(i::text, 5), lpad(d::text, 5);
END IF;
END LOOP;
PERFORM dblink_disconnect();
END;
$$ LANGUAGE plpgsql;
NOTICE: i = 1000, exectime = 0.524
NOTICE: i = 2000, exectime = 0.739
NOTICE: i = 3000, exectime = 1.188
NOTICE: i = 4000, exectime = 2.508
NOTICE: i = 5000, exectime = 1.791
NOTICE: i = 6000, exectime = 2.658
NOTICE: i = 7000, exectime = 2.318
NOTICE: i = 8000, exectime = 2.572
NOTICE: i = 9000, exectime = 2.929
NOTICE: i = 10000, exectime = 3.808
ืื ืงืจื? ืืื ืืคืืื ืืขืืืื ืืคืฉืื ืืืืชืจ ืฉื ืจืฉืืื ืืืืืช ืืื ืืืืฆืืข ืืจื ืคื 7 - ื-0.524ms ื-3.808ms? ืืืืืจืื ืฉืื ื ื ืื ื ืืืชืจ ืืืืชืจ ืืื.
ืืื ืืืฉืืช MVCC.
ืื ืืื ืขื
VACUUM VERBOSE tbl;
INFO: vacuuming "public.tbl"
INFO: "tbl": found 0 removable, 10026 nonremovable row versions in 45 out of 45 pages
DETAIL: 10000 dead row versions cannot be removed yet, oldest xmin: 597439602
ืื, ืืื ืื ืื ืงืืช! ืึทืงึฐืึผึดืื ืืงืฉืช ืืจืืฆื ืืคืจืืขื ืื ื - ืืจื ืืืื ืืชืืฉืื ืืจืฆื ืืคื ืืช ืืืจืกืืืช ืืืื (ืื ืื?), ืืื ืืืืจืืช ืืืืืช ืืืื ืืช ืขืืืจื. ืืืื ืื ืืืงืื ืืื ืื ืืขืืืจ ืื ื.
"ืืืืื" ืืช ืืฉืืืื
ืืื ืื ืื ื ืืืืขืื ืืืืืืืช ืฉืืฉืืืืชื ืืื ืื ืฆืจืืื ืืช ืืืืื ืฉืื ื. ืืื, ืขืืืื ื ื ืกื ืืืืืืจ ืืช ืืืฆืืขื ืืืขืจืืช ืืืืืืืช ื ืืืชืืช ืขื ืืื ืืืืื ืื ืืืืชืจ ืืืืืื - ืืคืืืช "ืืื ืืช", ืืืืืื ืฉ-VACUUM ืืืืชืจ.
ืืื ืืืืืืจ ืืืชืจ, ืืืื ื ืกืชืื ืขื ืืืืืื ืฉื ืืืงืจื ืฉื ืืืืช ืืืฅ. ืืืืืจ, ืืฉ ืืจืืื ืืืืื ืฉื INSERT/DELETE, ืืืคืขืืื ืืืืื ืจืืงื ืืืืจื. ืืื ืื ืื ืื ืจืืง, ืื ืื ื ืืืืืื ืืฉืืืจ ืืช ืืชืืื ืื ืืืื ืฉืื.
#0: ืืขืจืืช ืืืฆื
ืืจืืจ ืฉืืคืฉืจ ืื ืกืืช ืืขืฉืืช ืืฉืื ืขื ืืืืื ืื ืืืจื ืื ืคืขืืื, ืืื ืื ืื ืืืืื ื ืืืืืื - ืชืงืืจื ืืชืืืืงื ืชืืื ืืืืจืืจ ืืืืื ืืืชืคืืงื ืฉื ืฉืืืืชืืช ืืืขื.
ืืืื ื ื ืกื ืืช ืืงืจืืืจืืื ืื - "ืืืืข ืืืื ืืคืขืื" ืื:
- VACUUM ืืืฉืง ืืคื ื ืื ืืจืื ืืื
ืื ื ืืฆืคืื ืืขืืืก ืืื, ืื ืชื ืืื ืืืืืช 60 ืฉื ืืืช ืืื ืืืืืงืื [ืืืืืืื] ืืืืจืื. - ืืืื ืืฉืืืื ืืคืืื ืืืื ืืืืขื
ืืื ื ืืืืจ ืืช ืื ืืืกืคืจ ืืคืื ืฉื ืขืืืืื (ืืืืงืื ืฉื 8KB) ืืืืก ืืืืื ืืืื ืืืื - 1 blk ืขืืืจ ืขืจืืื + 1 blk ืขืืืจ ืื ืืื - ืขืืืจ ืฉืืืื ืฉืขืืื ืืืืืช ืจืืง. ืื ืื ื ืืฆืคืื ืฉืืืืช ืืกืืืืช ืฉื ื ืชืื ืื ืชืืื ืชืืฉืืจ ืืืืืจ "ืืืจื ืืื", ืกืืืจ ืืฉื ืืช ืืช ืื ืืกืื ืืื.
ืืงืฉืช ืืืืืช
SELECT
relpages
, ((
SELECT
count(*)
FROM
pg_index
WHERE
indrelid = cl.oid
) + 1) << 13 size_norm -- ััั ะฟัะฐะฒะธะปัะฝะตะต ะดะตะปะฐัั * current_setting('block_size')::bigint, ะฝะพ ะบัะพ ะผะตะฝัะตั ัะฐะทะผะตั ะฑะปะพะบะฐ?..
, pg_total_relation_size(oid) size
, coalesce(extract('epoch' from (now() - greatest(
pg_stat_get_last_vacuum_time(oid)
, pg_stat_get_last_autovacuum_time(oid)
))), 1 << 30) vaclag
FROM
pg_class cl
WHERE
oid = $1::regclass -- tbl
LIMIT 1;
relpages | size_norm | size | vaclag
-------------------------------------------
0 | 24576 | 1105920 | 3392.484835
ืืก' 1: ืขืืืื ืืืงืื
ืื ืื ื ืื ืืืืืื ืืืขืช ืืจืืฉ ืื ืฉืืืืชื ืืงืืืื ืืคืจืืขื ืื ื ืืืืคื ืืฉืืขืืชื - ืืื ืจืฉืืืืช ืืืืืง ืืคืื "ืื ืืขืืืื ืืช" ืืื ืฉืืืื. ืืื, ืืืฉืจ ืื ื ืืืืืืื ืืืืฉืื ืืขืื ืืช ืืืืื, ืืื ืืงืจื, ืขืืื ื ืงืืื ืื ืืืฆืข ืขืืื ืึดืฉืึฐืืึนื - ืื ืืืื ื-VACUUM FULL, ืืื ืืื ื ืืคืจืืข ืืชืืืืืื ืืงืืืืื ืืขืืืื ืขื ื ืชืื ืื ืฉื ืงืจืืื-ืืชืืื.
ืืื ืขื ืืืช, ืืื ืืืื ืื ืงืืช ืืื ืืช ืจืื ืื ืฉื ืจืฆื ืืืกืืจ. ืื, ืืฉืืืืชืืช ืขืืงืืืช ืืืืื ืื ืืขืืจื ืืืื ื ืืคื "ืืืืื ืื", ืืฉืจ ืืงืืื ืืช ืืฉื ืืืื ืฉืืื - ืืืคืืื, ืืช ืืฉื ืืืื ืืืืื ืฉื ืืกืืืช ืืืจืื ืขื ืืื ืขืกืงืช ืืฉืืจืืช ืฉืื ื.
ืืก' 2: ืืืฉืื ืืืืช?
ืืื ื ืืืืง ืื ืืฉ ืืฉืื ืืืืื ืืืื:
TABLE tbl LIMIT 1;
ืื ืื ื ืฉืืจื ืจืฉืืื ืืืช, ื ืืื ืืืกืื ืืจืื ืืขืืืื ืขื ืืื ืืืฆืืข ืคืฉืื
ืื ืคืืขื ืืื ืคืงืืืช DELETE ืืื ืชื ืื ืขืืืจ ืื ืืืื, ืืื ืืื ืืจืื ืืืชืจ ืืืืจ ืืืืืื ืฉืืื ืื ืกืืจืง ืืช ืืืืืืืช ืืคืืขื. ืืชืจื ืืื, ืืื ืืคื ื ืืื ืฉืื ืืืกืง, ืื ืฉืืื ืฆืืจื ืืืฆืข ืคืขืืืช VACUUM ืืืืจ ืืื.
ืื ืืชื ืฆืจืื ืืืคืก ืืช ืืื ื ืจืฆืฃ ืืืืื (Restart IDENTITY) ืชืืื ืื ืืืืืื.
ืืก' 3: ืืืื - ืืชืืืคืื!
ืืืืืื ืฉืื ืื ื ืขืืืืื ืืกืืืื ืืืื ืชืืจืืชืืช, ืืืื ืฉืื ืื ื ืืื ืืืืงืื ืฉืืื ืขืจืืื ืืืืื, ืืืฉืื ืืืจ ืืืื ืืื ืืืชืื ืฉื ืืฉืื. ืืกืืจ ืื ื ืืืื ืืช ืืืืืข ืืื, ืื ืื? ืื ื ืืื, ืื ืื ื ืฆืจืืืื ืืืืื ืฉืืฃ ืืื ืื ืืืื ืืจืฉืื ืืช ืื ืืืืืืืช.
ืืฉื ืื ืขืืื ื ืืืคืขืื ื ืืชื ืืกืืืจื-ืืืืื ืืขืกืงื ืฉืื ื (ืื, ืืื ืื ืื ื ืืชืืืืื ืขืกืงื) ืื ืืขืืื ืืช ืืืืื "ืืืื":
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
LOCK TABLE tbl IN ACCESS EXCLUSIVE MODE;
ืจืืช ืืกืืื ืื ื ืงืืขืช ืืคื ืืคืขืืืืช ืฉืื ื ืจืืฆืื ืืืฆืข ืขืืื.
#4: ื ืืืื ืขื ืืื ืื
ืื ืื ื ืืืื ืืืื ืืจืืฆืื "ืื ืขืื" ืืช ืืฉืื - ืื ืื ืืืฉืื ืืื ืคืขืื ืื ืืืืชื ืจืืข, ืืืฉื, ืงืจื ืืื ื? ืื ืื ื "ื ืชืื" ืืืืชื ื ืืฉืืจืืจ ืืืืืง ืืื, ืืืืจืื ืฉืจืืฆืื ืืงืจืื ืืืชืงืื ืื ื...
ืืื ืฉืื ืื ืืงืจื, "ื ืงืจืื ืืช ืขืฆืื ื" - ืื ืื ืืฆืืื ื ืืืฉืื ื ืขืืื ืชืื ืืื ืืกืืื (ืงืฆืจ ืืงืืื), ืื ื ืงืื ืืจืืื ืืืืกืืก, ืืื ืืคืืืช ืื ื ืชืขืจื ืืืชืจ ืืื. ืืืจืื.
ืืฉื ืื, ืืืืจ ืืช ืืฉืชื ื ืืืคืขืื
SET statement_timeout = ...;LOCK TABLE ...;
ืืื ืฉืื ื ืฆืืจื ืืืชืืืื ืขื ืฉืืืืจ ืืขืจื ื"ืืฉื" ืฉื ืืืฉืชื ื ืืืืืจ ืืืชืจ, ืื ื ืืฉืชืืฉืื ืืืืคืก ืืืืจ ืืงืืื, ืฉืืืืื ืืช ืืืงืฃ ืืืืืจื ืืขืกืงื ืื ืืืืืช.
ืื ื ืืืืจืื ืฉ- statement_timeout ืื ืขื ืื ืืืงืฉืืช ืืืืืช ืื ืฉืืขืกืงื ืื ืืืืื ืืืืืชื ืืขืจืืื ืืืชื ืืงืืืืื ืื ืืฉ ืืจืื ื ืชืื ืื ืืืืื.
ืืก' 5: ืืขืชืง ื ืชืื ืื
ืื ืืืืื ืืื ื ืจืืงื ืืืืืืื, ืืืื ืฆืืจื ืืฉืืืจ ืืืืฉ ืืช ืื ืชืื ืื ืืืืฆืขืืช ืืืื ืืื ืืช ืขืืจ:
CREATE TEMPORARY TABLE _tmp_swap ON COMMIT DROP AS TABLE tbl;
ืึฒืชึดืืึธื ON COMMIT DROP ืืืืจ ืฉืืจืืข ืฉืืขืกืงื ืืกืชืืืืช, ืืืืื ืืืื ืืช ืชืคืกืืง ืืืชืงืืื, ืืืื ืฆืืจื ืืืืืง ืืืชื ืืื ืืช ืืืงืฉืจ ืืืืืืจ.
ืืืืืื ืฉืื ื ืื ืืืื ืฉืืื ืืจืื ื ืชืื ืื "ืืืื", ืืคืขืืื ืืื ืฆืจืืื ืืืชืจืืฉ ืื ืืืจ.
ืืื ืื ืืื! ืื ืชืฉืื ืืืืจ ืืฉืืืช ืืขืกืงื
ืืจืืืช ืืชืกืจืื ืืกืืคื
ืื ื ืืฉืชืืฉืื ื"ืคืกืืืื-ืคืืชืื" ืืื:
# ัะพะฑะธัะฐะตะผ ััะฐัะธััะธะบั ั ัะฐะฑะปะธัั
stat <-
SELECT
relpages
, ((
SELECT
count(*)
FROM
pg_index
WHERE
indrelid = cl.oid
) + 1) << 13 size_norm
, pg_total_relation_size(oid) size
, coalesce(extract('epoch' from (now() - greatest(
pg_stat_get_last_vacuum_time(oid)
, pg_stat_get_last_autovacuum_time(oid)
))), 1 << 30) vaclag
FROM
pg_class cl
WHERE
oid = $1::regclass -- table_name
LIMIT 1;
# ัะฐะฑะปะธัะฐ ะฑะพะปััะต ัะตะปะตะฒะพะณะพ ัะฐะทะผะตัะฐ ะธ VACUUM ะฑัะป ะดะฐะฒะฝะพ
if stat.size > 2 * stat.size_norm and stat.vaclag is None or stat.vaclag > 60:
-> VACUUM %table;
try:
-> BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
# ะฟััะฐะตะผัั ะทะฐั
ะฒะฐัะธัั ะผะพะฝะพะฟะพะปัะฝัั ะฑะปะพะบะธัะพะฒะบั ั ะฟัะตะดะตะปัะฝัะผ ะฒัะตะผะตะฝะตะผ ะพะถะธะดะฐะฝะธั 1s
-> SET LOCAL statement_timeout = '1s'; SET LOCAL lock_timeout = '1s';
-> LOCK TABLE %table IN ACCESS EXCLUSIVE MODE;
# ะฝะฐะดะพ ัะฑะตะดะธัััั ะฒ ะฟัััะพัะต ัะฐะฑะปะธัั ะฒะฝัััะธ ััะฐะฝะทะฐะบัะธะธ ั ะฑะปะพะบะธัะพะฒะบะพะน
row <- TABLE %table LIMIT 1;
# ะตัะปะธ ะฒ ัะฐะฑะปะธัะต ะฝะตั ะฝะธ ะพะดะฝะพะน "ะถะธะฒะพะน" ะทะฐะฟะธัะธ - ะพัะธัะฐะตะผ ะตะต ะฟะพะปะฝะพัััั, ะฒ ะฟัะพัะธะฒะฝะพะผ ัะปััะฐะต - "ะฟะตัะตะฒััะฐะฒะปัะตะผ" ะฒัะต ะทะฐะฟะธัะธ ัะตัะตะท ะฒัะตะผะตะฝะฝัั ัะฐะฑะปะธัั
if row is None:
-> TRUNCATE TABLE %table RESTART IDENTITY;
else:
# ัะพะทะดะฐะตะผ ะฒัะตะผะตะฝะฝัั ัะฐะฑะปะธัั ั ะดะฐะฝะฝัะผะธ ัะฐะฑะปะธัั-ะพัะธะณะธะฝะฐะปะฐ
-> CREATE TEMPORARY TABLE _tmp_swap ON COMMIT DROP AS TABLE %table;
# ะพัะธัะฐะตะผ ะพัะธะณะธะฝะฐะป ะฑะตะท ัะฑัะพัะฐ ะฟะพัะปะตะดะพะฒะฐัะตะปัะฝะพััะธ
-> TRUNCATE TABLE %table;
# ะฒััะฐะฒะปัะตะผ ะฒัะต ัะพั
ัะฐะฝะตะฝะฝัะต ะฒะพ ะฒัะตะผะตะฝะฝะพะน ัะฐะฑะปะธัะต ะดะฐะฝะฝัะต ะพะฑัะฐัะฝะพ
-> INSERT INTO %table TABLE _tmp_swap;
-> COMMIT;
except Exception as e:
# ะตัะปะธ ะผั ะฟะพะปััะธะปะธ ะพัะธะฑะบั, ะฝะพ ัะพะตะดะธะฝะตะฝะธะต ะฒัะต ะตัะต "ะถะธะฒะพ" - ัะปะพะฒะธะปะธ ัะฐะนะผะฐัั
if not isinstance(e, InterfaceError):
-> ROLLBACK;
ืืื ื ืืชื ืื ืืืขืชืืง ืืช ืื ืชืื ืื ืืฉื ืืช?ืืืืคื ืขืงืจืื ื, ืื ืืคืฉืจื ืื ืืืื ืืืืื ืขืฆืื ืืื ื ืงืฉืืจ ืืคืขืืืืืืช ืืืจืืช ืืฆื BL ืื FK ืืฆื DB:
CREATE TABLE _swap_%table(LIKE %table INCLUDING ALL);
INSERT INTO _swap_%table TABLE %table;
DROP TABLE %table;
ALTER TABLE _swap_%table RENAME TO %table;
ืืืื ื ืจืืฅ ืืช ืืกืงืจืืคื ืืืืืช ืืืงืืจ ืื ืืืืง ืืช ืืืืืื:
VACUUM tbl;
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET LOCAL statement_timeout = '1s'; SET LOCAL lock_timeout = '1s';
LOCK TABLE tbl IN ACCESS EXCLUSIVE MODE;
CREATE TEMPORARY TABLE _tmp_swap ON COMMIT DROP AS TABLE tbl;
TRUNCATE TABLE tbl;
INSERT INTO tbl TABLE _tmp_swap;
COMMIT;
relpages | size_norm | size | vaclag
-------------------------------------------
0 | 24576 | 49152 | 32.705771
ืืื ืืกืชืืจ! ืืืืื ืืฆืืืฆืื ืคื 50 ืืื ืืขืืืื ืื ืฉืื ืคืืขืืื ืืืืืจืืช.
ืืงืืจ: www.habr.com