wiki:AdvancedTopics

Version 1 (modified by 231067, 3 days ago) ( diff )

--

Напредна Тема

Декларативно партиционирање на податоци

Со цел да се обезбеди висока скалабилност на системот и оптимални перформанси при експоненцијален раст на податоците, во овој проект имплементиравме декларативно партиционирање на најоптоварените трансакциски табели: Message и Mentorship. Бидејќи овие табели содржат податоци кои природно растат низ времето, искористена е стратегијата RANGE Partitioning, каде податоците се логички поделени врз основа на нивниот датум на креирање (Timestamp за пораки и CreatedAt за менторства).

За да не се наруши интегритетот на постоечките податоци, креирани се паралелни партиционирани табели (Mentorship_Partitioned и Message_Partitioned). За овие табели дефинирани се следните физички партиции:

  • Годишни партиции: изолирани физички табели за тековниот и идниот оперативен период на факултетот (за 2024, 2025 и 2026 година). Ова овозможува лесно архивирање на старите податоци во иднина.
  • DEFAULT партиција: како безбедносен механизам, креирани се табелите mentorship_future и message_future. Сите податоци чиј датум не припаѓа во експлицитно дефинираните години ќе бидат рутирани тука, со што се спречува системско паѓање при внес на непланирани датуми.

Оптимизација преку локални индекси

Наместо еден масивен глобален индекс кој би ја забавил работата на целата база, на секоја физичка партиција се поставени посебни локални индекси. На пример, креирани се B-Tree индекси на колоните ChatID и UserID во секоја годишна партиција за пораките, што драстично го намалува времето за пребарување и го минимизира таканаречениот Write Overhead.

Миграција и Доказ за перформанси

За да се докаже функционалноста на архитектурата, извршена е симулација на миграција на податоци преку префрлање на 100,000 записи од оригиналната во партиционираната структура. При самиот INSERT, PostgreSQL интелигентно ги рутираше податоците во соодветните физички табели. Оваа рутирана дистрибуција е верификувана преку повик кон системската колона tableoid::regclass, каде јасно се гледа физичката локација на секој поединечен запис.

Крајната придобивка од оваа архитектура е Partition Pruning. При извршување на аналитички пребарувања (на пр. барање пораки исклучиво за 2024 година), EXPLAIN ANALYZE планот потврдува дека Query Optimizer-от ја скенира единствено табелата message_2024, додека останатите физички партиции целосно ги игнорира.

CREATE TABLE Mentorship_Partitioned
(
    ID                  BIGSERIAL,
    StudentID           BIGINT NOT NULL,
    MentorID            BIGINT NOT NULL,
    TopicSuggestionID   BIGINT NOT NULL,
    MentorshipTypeID    BIGINT NOT NULL,
    CreatedAt           DATE NOT NULL,

    PRIMARY KEY(ID, CreatedAt)
)
PARTITION BY RANGE (CreatedAt);


CREATE TABLE mentorship_2024
PARTITION OF Mentorship_Partitioned
FOR VALUES FROM ('2024-01-01')
TO ('2025-01-01');


CREATE TABLE mentorship_2025
PARTITION OF Mentorship_Partitioned
FOR VALUES FROM ('2025-01-01')
TO ('2026-01-01');


CREATE TABLE mentorship_2026
PARTITION OF Mentorship_Partitioned
FOR VALUES FROM ('2026-01-01')
TO ('2027-01-01');



CREATE TABLE mentorship_future
PARTITION OF Mentorship_Partitioned
DEFAULT;



CREATE INDEX idx_m2024_student
ON mentorship_2024(StudentID);

CREATE INDEX idx_m2025_student
ON mentorship_2025(StudentID);

CREATE INDEX idx_m2026_student
ON mentorship_2026(StudentID);


INSERT INTO Mentorship_Partitioned
(
    StudentID,
    MentorID,
    TopicSuggestionID,
    MentorshipTypeID,
    CreatedAt
)
VALUES
(
    1,
    2,
    3,
    1,
    '2025-06-15'
);


SELECT tableoid::regclass, *
FROM Mentorship_Partitioned;  CREATE TABLE Message_Partitioned
(
    ID BIGSERIAL,
    Content TEXT,
    isRead BOOLEAN,
    Timestamp TIMESTAMP NOT NULL,
    ChatID BIGINT NOT NULL,
    UserID BIGINT NOT NULL,

    PRIMARY KEY (ID, Timestamp)
)
PARTITION BY RANGE (Timestamp);


CREATE TABLE message_2024
PARTITION OF Message_Partitioned
FOR VALUES FROM ('2024-01-01')
TO ('2025-01-01');

CREATE TABLE message_2025
PARTITION OF Message_Partitioned
FOR VALUES FROM ('2025-01-01')
TO ('2026-01-01');

CREATE TABLE message_2026
PARTITION OF Message_Partitioned
FOR VALUES FROM ('2026-01-01')
TO ('2027-01-01');

CREATE TABLE message_future
PARTITION OF Message_Partitioned
DEFAULT;


CREATE INDEX idx_msg2024_chat
ON message_2024(ChatID);

CREATE INDEX idx_msg2025_chat
ON message_2025(ChatID);

CREATE INDEX idx_msg2026_chat
ON message_2026(ChatID);

CREATE INDEX idx_msg2024_user
ON message_2024(UserID);

CREATE INDEX idx_msg2025_user
ON message_2025(UserID);

CREATE INDEX idx_msg2026_user
ON message_2026(UserID);




INSERT INTO Message_Partitioned
(
    Content,
    isRead,
    Timestamp,
    ChatID,
    UserID
)
VALUES
(
    'Testing partitioning',
    false,
    '2025-04-10 12:00:00',
    1,
    1
);


SELECT tableoid::regclass, *
FROM Message_Partitioned;




INSERT INTO Message_Partitioned (ID, Content, isRead, Timestamp, ChatID, UserID)
SELECT ID, Content, isRead, Timestamp, ChatID, UserID
FROM Message
LIMIT 100000; 

ANALYZE Message_Partitioned;


EXPLAIN ANALYZE
SELECT *
FROM Message_Partitioned
WHERE Timestamp BETWEEN
'2024-01-01'
AND
'2024-12-31';


SELECT ID, Timestamp, Content 
FROM message_2024 
LIMIT 20;
Note: See TracWiki for help on using the wiki.