PostgreSQL හි විශාල වෙළුම් සඳහා සතයක් ඉතිරි කරන්න

විසින් මතු කරන ලද විශාල දත්ත ප්‍රවාහයන් පටිගත කිරීමේ මාතෘකාව දිගටම කරගෙන යාම කොටස් කිරීම පිළිබඳ පෙර ලිපිය, මෙයින් අපි ඔබට කළ හැකි ක්‍රම දෙස බලමු ගබඩා කර ඇති "භෞතික" ප්රමාණය අඩු කරන්න PostgreSQL හි, සහ සේවාදායක කාර්ය සාධනය කෙරෙහි ඔවුන්ගේ බලපෑම.

අපි කතා කරමු TOAST සැකසුම් සහ දත්ත පෙළගැස්වීම. "සාමාන්‍යයෙන්," මෙම ක්‍රම බොහෝ සම්පත් ඉතිරි නොකරනු ඇත, නමුත් යෙදුම් කේතය කිසිසේත් වෙනස් නොකර.

PostgreSQL හි විශාල වෙළුම් සඳහා සතයක් ඉතිරි කරන්න
කෙසේ වෙතත්, අපගේ අත්දැකීම් මේ සම්බන්ධයෙන් ඉතා ඵලදායී බවට පත් විය, මන්ද එහි ස්වභාවය අනුව ඕනෑම අධීක්ෂණයක් පාහේ ගබඩා කර ඇත බොහෝ විට ඇමුණුම් පමණි වාර්තාගත දත්ත අනුව. ඒ වෙනුවට තැටියට ලිවීමට දත්ත සමුදාය උගන්වන්නේ කෙසේදැයි ඔබ කල්පනා කරන්නේ නම් 200MB / s අඩක් පමණ - කරුණාකර පූසා යටතේ.

විශාල දත්ත වල කුඩා රහස්

රැකියා පැතිකඩ අනුව අපගේ සේවාව, ඔවුන් නිතිපතා ගුහාවෙන් ඔහු වෙත පියාසර කරති පෙළ පැකේජ.

සහ එතැන් සිට VLSI සංකීර්ණයඅපි නිරීක්ෂණය කරන දත්ත සමුදාය සංකීර්ණ දත්ත ව්‍යුහයන් සහිත බහු සංරචක නිෂ්පාදනයක් වන අතර පසුව විමසුම් උපරිම කාර්ය සාධනය සඳහා මේ වගේ හැරෙනවා සංකීර්ණ ඇල්ගොරිතම තර්කනය සහිත "බහු-පරිමාව". එබැවින් අප වෙත පැමිණෙන ලඝු-සටහනේ එක් එක් ඉල්ලීමේ එක් එක් අවස්ථාවෙහි පරිමාව හෝ එහි ප්‍රතිඵලයක් ලෙස ක්‍රියාත්මක කිරීමේ සැලැස්ම “සාමාන්‍යයෙන්” තරමක් විශාල වේ.

අපි “අමු” දත්ත ලියන එක් වගුවක ව්‍යුහය දෙස බලමු - එනම්, ලොග් ප්‍රවේශයේ මුල් පෙළ මෙන්න:

CREATE TABLE rawdata_orig(
  pack -- PK
    uuid NOT NULL
, recno -- PK
    smallint NOT NULL
, dt -- ключ секции
    date
, data -- самое главное
    text
, PRIMARY KEY(pack, recno)
);

සාමාන්‍ය ලකුණක් (දැනටමත් කොටස් කර ඇත, ඇත්ත වශයෙන්ම, මෙය අංශ අච්චුවකි), එහිදී වඩාත්ම වැදගත් දෙය පෙළ වේ. සමහර විට තරමක් විශාලයි.

PG එකක එක් වාර්තාවක “භෞතික” ප්‍රමාණයට දත්ත එක් පිටුවකට වඩා ගත නොහැකි බව මතක තබා ගන්න, නමුත් “තාර්කික” ප්‍රමාණය සම්පූර්ණයෙන්ම වෙනස් කාරණයකි. ක්ෂේත්‍රයකට පරිමාමිතික අගයක් (varchar/text/bytea) ලිවීමට, භාවිතා කරන්න TOAST තාක්ෂණය:

PostgreSQL ස්ථාවර පිටු ප්‍රමාණය (සාමාන්‍යයෙන් 8 KB) භාවිතා කරයි, සහ tuples හට පිටු කිහිපයක් පුරා විහිදීමට ඉඩ නොදේ. එබැවින්, ඉතා විශාල ක්ෂේත්ර අගයන් සෘජුවම ගබඩා කළ නොහැක. මෙම සීමාව මඟහරවා ගැනීම සඳහා, විශාල ක්ෂේත්‍ර අගයන් සම්පීඩිත සහ/හෝ බහු භෞතික රේඛා හරහා බෙදී ඇත. මෙය පරිශීලකයාගේ අවධානයට ලක් නොවී සිදුවන අතර බොහෝ සේවාදායක කේතයන් කෙරෙහි අඩු බලපෑමක් ඇති කරයි. මෙම ක්‍රමය TOAST ලෙස හැඳින්වේ...

ඇත්ත වශයෙන්ම, "විභව විශාල" ක්ෂේත්‍ර සහිත සෑම වගුවක් සඳහාම, ස්වයංක්‍රීයව "පෙති" සහිත යුගල වගුවක් සාදනු ලැබේ එක් එක් "විශාල" වාර්තාව 2KB කොටස් වල:

TOAST(
  chunk_id
    integer
, chunk_seq
    integer
, chunk_data
    bytea
, PRIMARY KEY(chunk_id, chunk_seq)
);

එනම්, අපට "විශාල" අගයක් සහිත තන්තුවක් ලිවිය යුතු නම් data, එවිට සැබෑ පටිගත කිරීම සිදුවනු ඇත ප්රධාන වගුව සහ එහි PK වෙත පමණක් නොව, TOAST සහ එහි PK වෙතද.

TOAST බලපෑම අඩු කිරීම

නමුත් අපගේ බොහෝ වාර්තා තවමත් එතරම් විශාල නොවේ, 8KB වලට ගැලපෙන්න ඕන - මම මේ සඳහා මුදල් ඉතිරි කරන්නේ කෙසේද?..

ගුණාංගය අපගේ උපකාරයට පැමිණෙන්නේ මෙහිදීය STORAGE වගු තීරුවේ:

  • දීර්. කර ඇත සම්පීඩනය සහ වෙනම ගබඩා කිරීම යන දෙකටම ඉඩ සලසයි. මෙය සම්මත විකල්පය බොහෝ TOAST අනුකූල දත්ත වර්ග සඳහා. එය මුලින්ම සම්පීඩනය කිරීමට උත්සාහ කරයි, පසුව පේළිය තවමත් විශාල නම් මේසයෙන් පිටත ගබඩා කරයි.
  • ප්‍රධාන සම්පීඩනයට ඉඩ දෙන නමුත් වෙනම ගබඩා නොවේ. (ඇත්ත වශයෙන්ම, එවැනි තීරු සඳහා වෙනම ගබඩා කිරීම තවමත් සිදු කරනු ඇත, නමුත් පමණි අවසාන විසඳුම ලෙස, පිටුවට ගැළපෙන පරිදි තන්තුව හැකිලීමට වෙනත් ක්‍රමයක් නොමැති විට.)

ඇත්ත වශයෙන්ම, පෙළ සඳහා අපට අවශ්‍ය වන්නේ මෙයයි - එය හැකිතාක් සම්පීඩනය කරන්න, එය කිසිසේත් නොගැලපේ නම්, එය TOAST තුළ තබන්න. මෙය එක් විධානයකින් සෘජුවම පියාසර කළ හැක:

ALTER TABLE rawdata_orig ALTER COLUMN data SET STORAGE MAIN;

බලපෑම තක්සේරු කරන්නේ කෙසේද

දත්ත ප්‍රවාහය සෑම දිනකම වෙනස් වන බැවින්, අපට නිරපේක්ෂ සංඛ්‍යා සැසඳිය නොහැක, නමුත් සාපේක්ෂ වශයෙන් කුඩා කොටස අපි එය TOAST හි ලියා තැබුවෙමු - වඩා හොඳය. නමුත් මෙහි අනතුරක් තිබේ - එක් එක් වාර්තාවේ “භෞතික” පරිමාව විශාල වන තරමට, දර්ශකය “පුළුල්” බවට පත් වේ, මන්ද අපට තවත් දත්ත පිටු ආවරණය කිරීමට සිදුවේ.

අංශය වෙනස්කම් වලට පෙර:

heap  = 37GB (39%)
TOAST = 54GB (57%)
PK    =  4GB ( 4%)

අංශය වෙනස්කම් වලින් පසුව:

heap  = 37GB (67%)
TOAST = 16GB (29%)
PK    =  2GB ( 4%)

ඇත්ත වශයෙන්ම, අපි 2 ගුණයකින් අඩුවෙන් TOAST වෙත ලිවීමට පටන් ගත්තේය, එය තැටිය පමණක් නොව CPU ද මුදා හරින ලදී:

PostgreSQL හි විශාල වෙළුම් සඳහා සතයක් ඉතිරි කරන්න
PostgreSQL හි විශාල වෙළුම් සඳහා සතයක් ඉතිරි කරන්න
“ලිවීම” පමණක් නොව, තැටිය “කියවීම” තුළද අප කුඩා වී ඇති බව මම සටහන් කරමි - වාර්තාවක් වගුවකට ඇතුළු කරන විට, එය තීරණය කිරීම සඳහා එක් එක් දර්ශකයේ ගසේ කොටසක් “කියවීමට” අපට සිදුවේ. ඔවුන් තුළ අනාගත තත්ත්වය.

PostgreSQL 11 හි හොඳින් ජීවත් විය හැක්කේ කාටද?

PG11 වෙත යාවත්කාලීන කිරීමෙන් පසුව, අපි TOAST “සුසර කිරීම” දිගටම කරගෙන යාමට තීරණය කළ අතර මෙම අනුවාදයෙන් ආරම්භ වන පරාමිතිය සුසර කිරීම සඳහා ලබා ගත හැකි බව දුටුවෙමු. toast_tuple_target:

TOAST සැකසුම් කේතය දැල්වෙන්නේ වගුවේ ගබඩා කළ යුතු පේළි අගය TOAST_TUPLE_THRESHOLD බයිට (සාමාන්‍යයෙන් 2 KB) වඩා විශාල වූ විට පමණි. පේළියේ අගය TOAST_TUPLE_TARGET බයිට් (විචල්‍ය අගය, සාමාන්‍යයෙන් 2 KB) ට වඩා අඩු වන තුරු හෝ ප්‍රමාණය අඩු කළ නොහැකි වන තෙක් TOAST කේතය සංකෝචනය සහ/හෝ ක්ෂේත්‍ර අගයන් වගුවෙන් පිටතට ගෙන යනු ඇත.

සාමාන්‍යයෙන් අප සතුව ඇති දත්ත “ඉතා කෙටි” හෝ “ඉතා දිගු” බව අපි තීරණය කළෙමු, එබැවින් හැකි අවම අගයට සීමා කිරීමට අපි තීරණය කළෙමු:

ALTER TABLE rawplan_orig SET (toast_tuple_target = 128);

නැවත සකස් කිරීමෙන් පසු තැටි පැටවීමට නව සැකසුම් බලපෑවේ කෙසේදැයි බලමු:

PostgreSQL හි විශාල වෙළුම් සඳහා සතයක් ඉතිරි කරන්න
නරක නැහැ! සාමාන්යය තැටියේ පෝලිම අඩු වී ඇත ආසන්න වශයෙන් 1.5 ගුණයක්, සහ තැටිය "කාර්යබහුල" සියයට 20 කි! නමුත් මෙය කෙසේ හෝ CPU එකට බලපෑවේ ද?

PostgreSQL හි විශාල වෙළුම් සඳහා සතයක් ඉතිරි කරන්න
අවම වශයෙන් එය නරක අතට හැරුනේ නැත. කෙසේ වෙතත්, එවැනි වෙළුම්වලට පවා සාමාන්‍ය CPU භාරය ඉහළ නැංවිය නොහැකි දැයි විනිශ්චය කිරීම දුෂ්කර ය 5%.

නියමවල ස්ථාන වෙනස් කිරීමෙන්, එකතුව... වෙනස් වේ!

ඔබ දන්නා පරිදි, සතයක් රුබල් එකක් ඉතිරි කරයි, සහ අපගේ ගබඩා පරිමාව සමඟ එය ගැන 10TB/මාසය කුඩා ප්‍රශස්තිකරණයකින් පවා හොඳ ලාභයක් ලබා ගත හැකිය. එමනිසා, අපි අපගේ දත්තවල භෞතික ව්‍යුහය කෙරෙහි අවධානය යොමු කළෙමු - හරියටම කෙසේද වාර්තාව ඇතුළත "ස්ටැක්ඩ්" ක්ෂේත්ර එක් එක් වගු.

නිසා දත්ත පෙළගැස්ම මෙය කෙළින්ම ඉදිරියට ය ප්රතිඵලයක් ලෙස පරිමාවට බලපායි:

බොහෝ ගෘහ නිර්මාණ ශිල්පයන් යන්ත්‍ර වචන මායිම් මත දත්ත පෙළගැස්වීම සපයයි. උදාහරණයක් ලෙස, 32-bit x86 පද්ධතියක, නිඛිල (නිඛිල වර්ගය, බයිට් 4) ද්විත්ව නිරවද්‍ය පාවෙන ලක්ෂ්‍ය සංඛ්‍යා (ද්විත්ව නිරවද්‍ය පාවෙන ලක්ෂ්‍යය, බයිට් 4) මෙන් 8-බයිට් වචන මායිමකට පෙළගස්වනු ඇත. තවද 64-bit පද්ධතියක, ද්විත්ව අගයන් 8-byte වචන මායිම්වලට පෙළගස්වනු ඇත. මෙය නොගැලපීම සඳහා තවත් හේතුවකි.

පෙළගැස්ම හේතුවෙන්, වගු පේළියක විශාලත්වය ක්ෂේත්‍රවල අනුපිළිවෙල මත රඳා පවතී. සාමාන්යයෙන් මෙම බලපෑම ඉතා කැපී පෙනෙන නොවේ, නමුත් සමහර අවස්ථාවලදී එය ප්රමාණයෙන් සැලකිය යුතු වැඩි වීමක් ඇති විය හැක. උදාහරණයක් ලෙස, ඔබ char(1) සහ නිඛිල ක්ෂේත්‍ර මිශ්‍ර කරන්නේ නම්, සාමාන්‍යයෙන් ඒවා අතර බයිට් 3ක් අපතේ යයි.

අපි කෘතිම ආකෘති සමඟ ආරම්භ කරමු:

SELECT pg_column_size(ROW(
  '0000-0000-0000-0000-0000-0000-0000-0000'::uuid
, 0::smallint
, '2019-01-01'::date
));
-- 48 байт

SELECT pg_column_size(ROW(
  '2019-01-01'::date
, '0000-0000-0000-0000-0000-0000-0000-0000'::uuid
, 0::smallint
));
-- 46 байт

පළමු නඩුවේ අමතර බයිට් කිහිපයක් පැමිණියේ කොහෙන්ද? ඒක සරලයි - 2-byte smallint 4-byte මායිම මත පෙළගස්වා ඇත ඊළඟ ක්ෂේත්‍රයට පෙර, සහ එය අවසාන එක වන විට, කිසිවක් නොමැති අතර පෙළගැස්වීමට අවශ්‍ය නැත.

න්‍යායට අනුව, සෑම දෙයක්ම හොඳයි, ඔබට කැමති පරිදි ක්ෂේත්‍ර නැවත සකස් කළ හැකිය. එක් වගුවක උදාහරණය භාවිතා කර එය සැබෑ දත්ත මත පරීක්ෂා කරමු, එහි දෛනික කොටස 10-15GB පමණ වේ.

ආරම්භක ව්යුහය:

CREATE TABLE public.plan_20190220
(
-- Унаследована from table plan:  pack uuid NOT NULL,
-- Унаследована from table plan:  recno smallint NOT NULL,
-- Унаследована from table plan:  host uuid,
-- Унаследована from table plan:  ts timestamp with time zone,
-- Унаследована from table plan:  exectime numeric(32,3),
-- Унаследована from table plan:  duration numeric(32,3),
-- Унаследована from table plan:  bufint bigint,
-- Унаследована from table plan:  bufmem bigint,
-- Унаследована from table plan:  bufdsk bigint,
-- Унаследована from table plan:  apn uuid,
-- Унаследована from table plan:  ptr uuid,
-- Унаследована from table plan:  dt date,
  CONSTRAINT plan_20190220_pkey PRIMARY KEY (pack, recno),
  CONSTRAINT chck_ptr CHECK (ptr IS NOT NULL),
  CONSTRAINT plan_20190220_dt_check CHECK (dt = '2019-02-20'::date)
)
INHERITS (public.plan)

තීරු අනුපිළිවෙල වෙනස් කිරීමෙන් පසු කොටස - හරියටම එකම ක්ෂේත්‍ර, වෙනස් අනුපිළිවෙලක්:

CREATE TABLE public.plan_20190221
(
-- Унаследована from table plan:  dt date NOT NULL,
-- Унаследована from table plan:  ts timestamp with time zone,
-- Унаследована from table plan:  pack uuid NOT NULL,
-- Унаследована from table plan:  recno smallint NOT NULL,
-- Унаследована from table plan:  host uuid,
-- Унаследована from table plan:  apn uuid,
-- Унаследована from table plan:  ptr uuid,
-- Унаследована from table plan:  bufint bigint,
-- Унаследована from table plan:  bufmem bigint,
-- Унаследована from table plan:  bufdsk bigint,
-- Унаследована from table plan:  exectime numeric(32,3),
-- Унаследована from table plan:  duration numeric(32,3),
  CONSTRAINT plan_20190221_pkey PRIMARY KEY (pack, recno),
  CONSTRAINT chck_ptr CHECK (ptr IS NOT NULL),
  CONSTRAINT plan_20190221_dt_check CHECK (dt = '2019-02-21'::date)
)
INHERITS (public.plan)

කොටසෙහි සම්පූර්ණ පරිමාව තීරණය වන්නේ "කරුණු" ගණන අනුව වන අතර එය බාහිර ක්රියාවලීන් මත පමණක් රඳා පවතී, එබැවින් අපි ගොඩේ ප්රමාණය බෙදමු (pg_relation_size) එහි ඇති වාර්තා ගණන අනුව - එනම්, අපට ලැබේ සත්‍ය ගබඩා කර ඇති වාර්තාවේ සාමාන්‍ය ප්‍රමාණය:

PostgreSQL හි විශාල වෙළුම් සඳහා සතයක් ඉතිරි කරන්න
පරිමාව අඩු 6%, මහා!

නමුත් සෑම දෙයක්ම ඇත්ත වශයෙන්ම එතරම් රෝස නොවේ - සියල්ලට පසු, දර්ශක වලදී අපට ක්ෂේත්‍ර අනුපිළිවෙල වෙනස් කළ නොහැක, සහ එබැවින් "පොදුවේ" (pg_total_relation_size) ...

PostgreSQL හි විශාල වෙළුම් සඳහා සතයක් ඉතිරි කරන්න
...තවමත් මෙතන ඉතිරි 1.5%එක කේතයක්වත් වෙනස් නොකර. ඔව් ඔව්!

PostgreSQL හි විශාල වෙළුම් සඳහා සතයක් ඉතිරි කරන්න

ක්ෂේත්‍ර සැකසීම සඳහා ඉහත විකල්පය එය වඩාත්ම ප්‍රශස්ත බව නොවන බව මම සටහන් කරමි. සෞන්දර්යාත්මක හේතූන් මත සමහර ක්ෂේත්‍ර කුට්ටි "ඉරීම" ඔබට අවශ්‍ය නැති නිසා - උදාහරණයක් ලෙස, යුවලක් (pack, recno), මෙම වගුව සඳහා PK යනු කුමක්ද?

සාමාන්යයෙන්, ක්ෂේත්රවල "අවම" සැකැස්ම නිර්ණය කිරීම තරමක් සරල "තිරිරු බලය" කාර්යයකි. එමනිසා, ඔබට ඔබගේ දත්ත වලින් අපගේ දත්ත වලට වඩා හොඳ ප්‍රතිඵල ලබා ගත හැක - එය උත්සාහ කරන්න!

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න