ื›ืืฉืจ ื•ืืงื•ื ื ื›ืฉืœ, ืื ื• ืžื ืงื™ื ืืช ื”ืฉื•ืœื—ืŸ ื‘ืื•ืคืŸ ื™ื“ื ื™

ืœึดืฉืึฐืื•ึนื‘ ื™ื›ื•ืœ "ืœื ืงื•ืช" ืžื˜ื‘ืœื” ื‘-PostgreSQL ืจืง ืžื” ืืฃ ืื—ื“ ืœื ื™ื›ื•ืœ ืœืจืื•ืช - ื›ืœื•ืžืจ, ืื™ืŸ ื‘ืงืฉื” ืคืขื™ืœื” ืื—ืช ืฉื”ืชื—ื™ืœื” ืœืคื ื™ ืฉื”ืจืฉื•ืžื•ืช ื”ืœืœื• ืฉื•ื ื•.

ืื‘ืœ ืžื” ืื ืกื•ื’ ื›ืœ ื›ืš ืœื ื ืขื™ื (ืขื•ืžืก 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);

ื›ืขืช ืื ื• ืžืขื“ื›ื ื™ื ืืช ื”ืขืจืš ืฉืœ ืื—ื“ ื”ืžื•ื ื™ื ืคืขืžื™ื ืจื‘ื•ืช. ืœืžืขืŸ ื˜ื•ื”ืจ ื”ื ื™ืกื•ื™, ื‘ื•ืื• ื ืขืฉื” ื–ืืช ื‘ืขืกืงืื•ืช ื ืคืจื“ื•ืช ื‘ืืžืฆืขื•ืช dblinkืื™ืš ื–ื” ื™ืงืจื” ื‘ืžืฆื™ืื•ืช:

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.

ื–ื” ื”ื›ืœ ืขืœ ืžื ื’ื ื•ืŸ 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: ื ื™ื’ื•ื“ ืขื ื™ื™ื ื™ื

ืื ื—ื ื• ื‘ืื™ื ืœื›ืืŸ ื•ืจื•ืฆื™ื "ืœื ืขื•ืœ" ืืช ื”ืฉืœื˜ - ืžื” ืื ืžื™ืฉื”ื• ื”ื™ื” ืคืขื™ืœ ื‘ื• ื‘ืื•ืชื• ืจื’ืข, ืœืžืฉืœ, ืงืจื ืžืžื ื•? ืื ื—ื ื• "ื ืชืœื”" ื‘ื”ืžืชื ื” ืœืฉื—ืจื•ืจ ื”ื‘ืœื•ืง ื”ื–ื”, ื•ืื—ืจื™ื ืฉืจื•ืฆื™ื ืœืงืจื•ื ื™ื™ืชืงืœื• ื‘ื ื•...

ื›ื“ื™ ืฉื–ื” ืœื ื™ืงืจื”, "ื ืงืจื™ื‘ ืืช ืขืฆืžื ื•" - ืื ืœื ื”ืฆืœื—ื ื• ืœื”ืฉื™ื’ ื ืขื™ืœื” ืชื•ืš ื–ืžืŸ ืžืกื•ื™ื (ืงืฆืจ ืžืงื•ื‘ืœ), ืื– ื ืงื‘ืœ ื—ืจื™ื’ื” ืžื”ื‘ืกื™ืก, ืื‘ืœ ืœืคื—ื•ืช ืœื ื ืชืขืจื‘ ื™ื•ืชืจ ืžื“ื™. ืื—ืจื™ื.

ืœืฉื ื›ืš, ื”ื’ื“ืจ ืืช ืžืฉืชื ื” ื”ื”ืคืขืœื” lock_timeout (ืขื‘ื•ืจ ื’ืจืกืื•ืช 9.3+) ืื•/ื• statement_timeout. ื”ื“ื‘ืจ ื”ืขื™ืงืจื™ ืฉื™ืฉ ืœื–ื›ื•ืจ ื”ื•ื ืฉื”ืขืจืš statement_timeout ื—ืœ ืจืง ืžื”ืžืฉืคื˜ ื”ื‘ื. ื›ืœื•ืžืจ, ื›ื›ื” ื‘ื”ื“ื‘ืงื” - ืœื ื™ืขื‘ื•ื“:

SET statement_timeout = ...;LOCK TABLE ...;

ื›ื“ื™ ืฉืœื ื ืฆื˜ืจืš ืœื”ืชืžื•ื“ื“ ืขื ืฉื—ื–ื•ืจ ื”ืขืจืš ื”"ื™ืฉืŸ" ืฉืœ ื”ืžืฉืชื ื” ืžืื•ื—ืจ ื™ื•ืชืจ, ืื ื• ืžืฉืชืžืฉื™ื ื‘ื˜ื•ืคืก ื”ื’ื“ืจ ืžืงื•ืžื™, ืฉืžื’ื‘ื™ืœ ืืช ื”ื™ืงืฃ ื”ื”ื’ื“ืจื” ืœืขืกืงื” ื”ื ื•ื›ื—ื™ืช.

ืื ื• ื–ื•ื›ืจื™ื ืฉ- statement_timeout ื—ืœ ืขืœ ื›ืœ ื”ื‘ืงืฉื•ืช ื”ื‘ืื•ืช ื›ืš ืฉื”ืขืกืงื” ืœื ื™ื›ื•ืœื” ืœื”ื™ืžืชื— ืœืขืจื›ื™ื ื‘ืœืชื™ ืžืงื•ื‘ืœื™ื ืื ื™ืฉ ื”ืจื‘ื” ื ืชื•ื ื™ื ื‘ื˜ื‘ืœื”.

ืžืก' 5: ื”ืขืชืง ื ืชื•ื ื™ื

ืื ื”ื˜ื‘ืœื” ืื™ื ื” ืจื™ืงื” ืœื—ืœื•ื˜ื™ืŸ, ื™ื”ื™ื” ืฆื•ืจืš ืœืฉืžื•ืจ ืžื—ื“ืฉ ืืช ื”ื ืชื•ื ื™ื ื‘ืืžืฆืขื•ืช ื˜ื‘ืœื” ื–ืžื ื™ืช ืขื–ืจ:

CREATE TEMPORARY TABLE _tmp_swap ON COMMIT DROP AS TABLE tbl;

ื—ึฒืชึดื™ืžึธื” ON COMMIT DROP ืื•ืžืจ ืฉื‘ืจื’ืข ืฉื”ืขืกืงื” ืžืกืชื™ื™ืžืช, ื”ื˜ื‘ืœื” ื”ื–ืžื ื™ืช ืชืคืกื™ืง ืœื”ืชืงื™ื™ื, ื•ืื™ืŸ ืฆื•ืจืš ืœืžื—ื•ืง ืื•ืชื” ื™ื“ื ื™ืช ื‘ื”ืงืฉืจ ื”ื—ื™ื‘ื•ืจ.

ืžื›ื™ื•ื•ืŸ ืฉืื ื• ืžื ื™ื—ื™ื ืฉืื™ืŸ ื”ืจื‘ื” ื ืชื•ื ื™ื "ื—ื™ื™ื", ื”ืคืขื•ืœื” ื”ื–ื• ืฆืจื™ื›ื” ืœื”ืชืจื—ืฉ ื“ื™ ืžื”ืจ.

ื˜ื•ื‘ ื–ื” ื”ื›ืœ! ืืœ ืชืฉื›ื— ืœืื—ืจ ื”ืฉืœืžืช ื”ืขืกืงื” ืœื”ืคืขื™ืœ ืืช ANALYZE ืœื ืจืžืœ ืกื˜ื˜ื™ืกื˜ื™ืงื•ืช ื˜ื‘ืœื” ื‘ืžื™ื“ืช ื”ืฆื•ืจืš.

ื”ืจื›ื‘ืช ื”ืชืกืจื™ื˜ ื”ืกื•ืคื™

ืื ื• ืžืฉืชืžืฉื™ื ื‘"ืคืกืื•ื“ื•-ืคื™ืชื•ืŸ" ื”ื–ื”:

# ัะพะฑะธั€ะฐะตะผ ัั‚ะฐั‚ะธัั‚ะธะบัƒ ั ั‚ะฐะฑะปะธั†ั‹
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

ื”ื•ืกืคืช ืชื’ื•ื‘ื”