Ṣugbọn kini ti iru iru alaiwu ba wa (ẹru OLAP igba pipẹ lori ibi ipamọ data OLTP) tun wa? Bawo mọ actively iyipada tabili ti yika nipasẹ gun yoowu ti ati ki o ko Akobaratan lori a àwárí?
Laying jade àwárí
Ni akọkọ, jẹ ki a pinnu kini iṣoro ti a fẹ yanju jẹ ati bii o ṣe le dide.
Nigbagbogbo ipo yii n ṣẹlẹ lori kan jo mo kekere tabili, ṣugbọn ninu eyiti o waye ọpọlọpọ awọn ayipada. Nigbagbogbo eyi tabi yatọ mita / aggregates /-wonsi, lori eyiti a ṣe imudojuiwọn nigbagbogbo, tabi saarin-isinyi lati ṣe ilana diẹ ninu awọn ṣiṣan ti nlọ lọwọ nigbagbogbo ti awọn iṣẹlẹ, awọn igbasilẹ eyiti o jẹ FI sii / Paarẹ nigbagbogbo.
Jẹ ki a gbiyanju lati tun ṣe aṣayan pẹlu awọn idiyele:
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;
Ati ni afiwe, ni asopọ miiran, gigun kan, ibeere gigun bẹrẹ, gbigba diẹ ninu awọn iṣiro eka, ṣugbọn ko ni ipa lori tabili wa:
SELECT pg_sleep(10000);
Bayi a ṣe imudojuiwọn iye ti ọkan ninu awọn onka ọpọlọpọ, ọpọlọpọ igba. Fun iwa mimọ ti idanwo, jẹ ki a ṣe eyi
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
Kini o ti ṣẹlẹ? Kini idi paapaa fun imudojuiwọn ti o rọrun julọ ti igbasilẹ kan akoko ipaniyan degraded nipa 7 igba - lati 0.524ms si 3.808ms? Ati pe idiyele wa n kọ diẹ sii ati siwaju sii laiyara.
Gbogbo rẹ jẹ ẹbi MVCC.
O jẹ gbogbo nipa
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
Oh, ko si nkankan lati nu! Ni afiwe Ibere ti nṣiṣẹ ti wa ni kikọlu pẹlu wa - lẹhinna, o le ni ọjọ kan fẹ lati yipada si awọn ẹya wọnyi (kini bi?), Ati pe wọn yẹ ki o wa fun u. Ati nitorinaa paapaa VACUUM FULL kii yoo ran wa lọwọ.
"Ti n ṣubu" tabili
Ṣugbọn a mọ daju pe ibeere yẹn ko nilo tabili wa. Nitorinaa, a yoo tun gbiyanju lati da iṣẹ ṣiṣe eto pada si awọn opin to pe nipa imukuro ohun gbogbo ti ko wulo lati tabili - o kere ju “pẹlu ọwọ”, nitori VACUUM funni ni.
Lati ṣe alaye diẹ sii, jẹ ki a wo apẹẹrẹ ti ọran ti tabili ifipamọ. Iyẹn ni, ṣiṣan nla ti fi sii / PA, ati nigba miiran tabili jẹ ofo patapata. Ṣugbọn ti ko ba ṣofo, a gbọdọ fi awọn oniwe-lọwọlọwọ awọn akoonu ti.
# 0: Iṣiro ipo naa
O han gbangba pe o le gbiyanju lati ṣe ohun kan pẹlu tabili paapaa lẹhin iṣiṣẹ kọọkan, ṣugbọn eyi ko ni oye pupọ - iṣaju itọju yoo han gbangba tobi ju igbejade ti awọn ibeere ibi-afẹde.
Jẹ ki a ṣe agbekalẹ awọn ibeere - “o to akoko lati ṣe” ti o ba jẹ:
- VACUUM ti ṣe ifilọlẹ ni igba pipẹ sẹhin
A n reti ẹru wuwo, nitorina jẹ ki o jẹ 60 aaya lati kẹhin [laifọwọyi] VACUUM. - iwọn tabili ti ara tobi ju ibi-afẹde lọ
Jẹ ki a ṣalaye rẹ bi ilọpo meji nọmba awọn oju-iwe (awọn bulọọki 8KB) ni ibatan si iwọn to kere julọ - 1 blk fun okiti + 1 blk fun atọka kọọkan - fun a oyi ṣofo tabili. Ti a ba nireti pe iye data kan yoo wa nigbagbogbo ninu ifipamọ “deede”, o jẹ oye lati tweak agbekalẹ yii.
Ijerisi ìbéèrè
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: Ṣi VACUUM
A ko le mọ tẹlẹ boya ibeere ti o jọra kan n ṣe idalọwọduro pẹlu wa ni pataki - ni deede iye awọn igbasilẹ ti “ti ti ọjọ” lati igba ti o ti bẹrẹ. Nitorinaa, nigba ti a pinnu lati ṣe ilana tabili bakan, ni eyikeyi ọran, o yẹ ki a kọkọ ṣiṣẹ lori rẹ ỌRỌ - ko dabi VACUUM FULL, ko dabaru pẹlu awọn ilana ti o jọra ti n ṣiṣẹ pẹlu data kika-kikọ.
Ni akoko kanna, o le sọ di mimọ pupọ julọ ohun ti a yoo fẹ lati yọ kuro. Bẹẹni, ati awọn ibeere ti o tẹle lori tabili yii yoo lọ si wa nipasẹ "cache gbona", eyiti yoo dinku iye akoko wọn - ati, nitorinaa, akoko lapapọ ti idinamọ awọn miiran nipasẹ iṣowo iṣẹ wa.
#2: Ṣe ẹnikẹni wa ni ile?
Jẹ ki a ṣayẹwo ti ohunkohun ba wa ninu tabili rara:
TABLE tbl LIMIT 1;
Ti ko ba si igbasilẹ kan ti o ku, lẹhinna a le ṣafipamọ pupọ lori sisẹ nipasẹ ṣiṣe nìkan
O ìgbésẹ kanna bi ohun unconditional Parẹ tabili fun kọọkan tabili, sugbon jẹ Elo yiyara niwon o ko ni kosi ọlọjẹ awọn tabili. Pẹlupẹlu, o yoo gba aaye disk laaye lẹsẹkẹsẹ, nitorinaa ko si iwulo lati ṣe iṣẹ VACUUM kan lẹhinna.
Boya o nilo lati tun counter tabili ṣeto (TTUN IDANỌ) jẹ fun ọ lati pinnu.
# 3: Gbogbo eniyan - ya awọn akoko!
Niwọn bi a ti n ṣiṣẹ ni agbegbe ifigagbaga pupọ, lakoko ti a wa nibi n ṣayẹwo pe ko si awọn titẹ sii ninu tabili, ẹnikan le ti kọ nkan tẹlẹ nibẹ. A ko yẹ ki o padanu alaye yii, nitorina kini? Iyẹn tọ, a nilo lati rii daju pe ko si ẹnikan ti o le kọ silẹ ni idaniloju.
Lati ṣe eyi a nilo lati mu ṣiṣẹ SERIALIZABLE-ipinya fun iṣowo wa (bẹẹni, nibi a bẹrẹ idunadura kan) ati tii tabili “ni wiwọ”:
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
LOCK TABLE tbl IN ACCESS EXCLUSIVE MODE;
Ipele ìdènà yii jẹ ipinnu nipasẹ awọn iṣẹ ṣiṣe ti a fẹ ṣe lori rẹ.
# 4: Rogbodiyan ti awọn anfani
A wa nibi ati fẹ lati “titiipa” ami naa - kini ti ẹnikan ba ṣiṣẹ lori rẹ ni akoko yẹn, fun apẹẹrẹ, kika lati inu rẹ? A yoo "duro" nduro fun bulọki yii lati tu silẹ, ati pe awọn miiran ti o fẹ ka yoo sare sinu wa…
Lati yago fun eyi lati ṣẹlẹ, a yoo “rubọ ara wa” - ti a ko ba le gba titiipa laarin akoko kan (iwọn itẹwọgba kukuru), lẹhinna a yoo gba imukuro lati ipilẹ, ṣugbọn o kere ju a kii yoo dabaru pupọ pẹlu awon miran.
Lati ṣe eyi, ṣeto oniyipada igba
SET statement_timeout = ...;LOCK TABLE ...;
Ni ibere ki o má ba ṣe pẹlu mimu-pada sipo iye "atijọ" ti oniyipada nigbamii, a lo fọọmu naa ṢETO IBILE, eyi ti o fi opin si ipari ti eto naa si iṣowo lọwọlọwọ.
A ranti pe gbólóhùn_timeout kan si gbogbo awọn ibeere ti o tẹle ki idunadura naa ko le na isan si awọn iye itẹwẹgba ti data pupọ ba wa ninu tabili.
#5: da data
Ti tabili ko ba ṣofo patapata, data naa yoo ni lati tun-fipamọ ni lilo tabili igba diẹ oluranlowo:
CREATE TEMPORARY TABLE _tmp_swap ON COMMIT DROP AS TABLE tbl;
Ibuwọlu LORI IFỌRỌWỌRỌ tumọ si pe ni akoko idunadura naa pari, tabili igba diẹ yoo dẹkun lati wa, ati pe ko si iwulo lati paarẹ pẹlu ọwọ ni ipo asopọ.
Niwọn igba ti a ro pe ko si pupọ data “ifiwe”, iṣẹ yii yẹ ki o waye ni iyara.
O dara, iyẹn ni gbogbo! Maṣe gbagbe lẹhin ipari idunadura naa
Nfi papo ik akosile
A lo “pseudo-python” yii:
# собираем статистику с таблицы
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;
Ṣe o ṣee ṣe lati ma daakọ data naa ni akoko keji?Ni opo, o ṣee ṣe ti epo tabili funrararẹ ko ba ni asopọ si awọn iṣẹ miiran lati ẹgbẹ BL tabi FK lati ẹgbẹ 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;
Jẹ ki a ṣiṣẹ iwe afọwọkọ lori tabili orisun ati ṣayẹwo awọn metiriki:
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
Ohun gbogbo ti ṣiṣẹ jade! Tabili naa ti dinku nipasẹ awọn akoko 50 ati pe gbogbo awọn imudojuiwọn nṣiṣẹ ni iyara lẹẹkansi.
orisun: www.habr.com