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/текст/байт) бичихийн тулд ашиглана уу TOAST технологи:

PostgreSQL нь тогтмол хуудасны хэмжээг (ихэвчлэн 8 KB) ашигладаг бөгөөд олон хуудас дамжихыг зөвшөөрдөггүй. Тиймээс маш том талбайн утгыг шууд хадгалах боломжгүй юм. Энэ хязгаарлалтыг даван туулахын тулд том талбайн утгуудыг шахаж, / эсвэл олон физик шугамаар хуваана. Энэ нь хэрэглэгчдэд мэдэгдэхгүйгээр тохиолддог бөгөөд ихэнх серверийн кодуудад бага нөлөө үзүүлдэг. Энэ аргыг 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%)

Үнэндээ бид TOAST руу 2 дахин бага бичиж эхэлсэн, энэ нь зөвхөн диск төдийгүй CPU-г буулгасан:

PostgreSQL дээр их хэмжээний мөнгө хэмнээрэй
PostgreSQL дээр их хэмжээний мөнгө хэмнээрэй
Бид зөвхөн "бичих" төдийгүй дискийг "унших" тал дээр багассан гэдгийг би тэмдэглэх болно, учир нь хүснэгтэд бичлэг оруулахдаа индекс бүрийн модны хэсгийг "унших" шаардлагатай болдог. тэдний ирээдүйн байр суурь.

PostgreSQL 11 дээр хэн сайн амьдарч чадах вэ

PG11-д шинэчлэгдсэний дараа бид TOAST-ыг "тохируулж" үргэлжлүүлэхээр шийдсэн бөгөөд энэ хувилбараас эхлэн параметрийг тааруулах боломжтой болсныг анзаарсан. toast_tuple_target:

Хүснэгтэд хадгалагдах мөрийн утга нь TOAST_TUPLE_THRESHOLD байт (ихэвчлэн 2 КБ)-аас их байх үед л TOAST боловсруулах код ажиллана. TOAST код нь мөрийн утга TOAST_TUPLE_TARGET байтаас (хувьсагчийн утга, мөн ихэвчлэн 2 КБ) бага болтол эсвэл хэмжээг багасгах боломжгүй болтол талбарын утгыг шахах ба/эсвэл хүснэгтээс зөөнө.

Бидэнд ихэвчлэн байдаг өгөгдөл нь "маш богино" эсвэл "маш урт" гэж шийдсэн тул бид боломжит хамгийн бага утгыг хязгаарлахаар шийдсэн:

ALTER TABLE rawplan_orig SET (toast_tuple_target = 128);

Дахин тохируулсны дараа шинэ тохиргоо нь дискийг ачаалахад хэрхэн нөлөөлсөнийг харцгаая.

PostgreSQL дээр их хэмжээний мөнгө хэмнээрэй
Муугүй шүү! Дундаж дискний дараалал багассан ойролцоогоор 1.5 дахин, диск "завгүй" 20 хувь байна! Гэхдээ энэ нь ямар нэгэн байдлаар CPU-д нөлөөлсөн болов уу?

PostgreSQL дээр их хэмжээний мөнгө хэмнээрэй
Наад зах нь бүр дордсонгүй. Гэсэн хэдий ч ийм хэмжээ нь CPU-ийн дундаж ачааллыг нэмэгдүүлэх боломжгүй хэвээр байгаа эсэхийг дүгнэхэд хэцүү байдаг 5%.

Нөхцөлүүдийн байрыг өөрчилснөөр нийлбэр... өөрчлөгдөнө!

Та бүхний мэдэж байгаагаар нэг пенни нэг рубль хэмнэдэг бөгөөд бидний хадгалах багтаамжтай энэ нь ойролцоогоор юм 10TB/сар бага зэрэг оновчлол ч гэсэн сайн ашиг авчирдаг. Тиймээс бид өгөгдлийнхөө физик бүтцэд анхаарлаа хандуулсан - яг яаж Бичлэг доторх "овоолсон" талбарууд хүснэгт бүр.

Учир нь өгөгдлийн тохируулга энэ бол шууд урагшаа үүссэн эзлэхүүнд нөлөөлдөг:

Олон архитектурууд нь машины үгийн хил дээр өгөгдлийн зэрэгцүүлэлтийг хангадаг. Жишээлбэл, 32 битийн x86 систем дээр бүхэл тоонууд (бүхэл тоон төрөл, 4 байт) 4 байт үгийн хязгаарт, мөн хоёр нарийвчлалтай хөвөх цэгийн тоо (давхар нарийвчлалтай хөвөх цэг, 8 байт) зэрэгцэх болно. Мөн 64 битийн систем дээр давхар утгыг 8 байт үгийн хязгаарт тохируулна. Энэ нь үл нийцэх бас нэг шалтгаан юм.

Зэрэгцүүлэхийн улмаас хүснэгтийн мөрийн хэмжээ нь талбаруудын дарааллаас хамаарна. Ихэнхдээ энэ нөлөө нь тийм ч мэдэгдэхүйц биш боловч зарим тохиолдолд хэмжээ нь мэдэгдэхүйц нэмэгдэхэд хүргэдэг. Жишээлбэл, хэрэв та 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 байт хил дээр зэрэгцүүлсэн 4 байт жижиг дараагийн талбараас өмнө, мөн энэ нь сүүлчийнх нь байх үед юу ч байхгүй бөгөөд тэгшлэх шаардлагагүй.

Онолын хувьд бүх зүйл хэвийн байгаа бөгөөд та талбайг хүссэнээрээ өөрчилж болно. Өдөр тутмын хэсэг нь 10-15 ГБ эзэлдэг хүснэгтийн жишээг ашиглан бодит өгөгдөл дээр үүнийг шалгая.

Анхны бүтэц:

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

сэтгэгдэл нэмэх