wiki:Phase4_Performance_Analysis

Version 7 (modified by 226052, 3 days ago) ( diff )

--

Мерење на перформанси

Извршена е анализа на перформансите на базата film_rental во PostgreSQL. Се споредуваат неоптимизирани табели и оптимизирани табели:

  • rental_copy - непартиционирана табела, користена како почетна состојба за споредба;
  • rental - партиционирана табела според rental_date, со дополнителни индекси;
  • payment_copy - непартиционирана табела за плаќања;
  • payment - партиционирана табела според payment_date, со индекс за датум и вработен.

За оваа анализа беше користено pgbench. Секој тест се извршува со повеќе паралелни клиенти, при што се мерат просечна латентност, standard deviation и TPS односно број на трансакции во секунда. Standard deviation покажува колку варира времето на извршување околу просечната латентност, па помала вредност значи постабилни и попредвидливи перформанси.

Пример за извршување на benchmark тест:

pgbench -n -U admin -d film_rental -c 10 -j 2 -T 60 -f /tmp/movie_recommendation_rental_copy.sql -l --log-prefix=/tmp/movie_recommendation_rental_copy_c10

Каде:

  • -n означува дека pgbench не ја иницијализира стандардната pgbench шема;
  • -U admin е корисникот со кој се поврзува кон базата;
  • -d film_rental е базата врз која се извршува тестот;
  • -c 10 означува 10 паралелни клиенти;
  • -j 2 означува 2 работни нишки;
  • -T 60 означува времетраење од 60 секунди;
  • -f ја задава SQL датотеката што се извршува.
  • --log-prefix ја задава патеката и префиксот на log датотеките во кои pgbench ги запишува резултатите.

Истата команда се повторуваше со различен број клиенти, на пример 10, 20, 30 и 50, и со SQL датотеки за неоптимизираната и оптимизираната верзија.

За пресметување на standard deviation од pgbench log датотеките се користеше следната awk команда:

awk '
$3 ~ /^[0-9]+$/ {
  n++;
  x=$3/1000;
  sum+=x;
  sumsq+=x*x
}
END {
  mean=sum/n;
  stddev=sqrt((sumsq - (sum*sum/n))/(n-1));
  printf "transactions=%d\nmean=%.3f ms\nstddev=%.3f ms\n", n, mean, stddev
}
' /tmp/movie_recommendation_rental_copy_c10*

Во log датотеките што ги генерира pgbench, секој ред претставува една извршена трансакција. Третата колона ($3) го содржи времето на извршување на таа трансакција, изразено во микросекунди. Бидејќи во табелите резултатите се прикажуваат во милисекунди, вредноста од третата колона се дели со 1000. Потоа од сите добиени вредности се пресметуваат просечната латентност и standard deviation.

Детални резултати

Q1 - Movie Recommendation

Прашалникот прави препорака на филмови за конкретен корисник. Се анализираат претходните изнајмувања, омилените категории, рејтинзите и популарноста на филмовите во 2024 година.

WITH customer_history AS (
    SELECT DISTINCT
        f.film_id,
        f.rating,
        fc.category_id
    FROM rental_copy r
    JOIN inventory i ON r.inventory_id = i.inventory_id
    JOIN film f ON i.film_id = f.film_id
    JOIN film_category fc ON f.film_id = fc.film_id
    WHERE r.customer_id = 101
),
preferred_categories AS (
    SELECT
        category_id,
        COUNT(*) AS category_score
    FROM customer_history
    GROUP BY category_id
),
candidate_films AS (
    SELECT
        f.film_id,
        f.title,
        f.rating,
        fc.category_id,
        pc.category_score
    FROM film f
    JOIN film_category fc ON f.film_id = fc.film_id
    JOIN preferred_categories pc ON fc.category_id = pc.category_id
    WHERE NOT EXISTS (
        SELECT 1
        FROM customer_history ch
        WHERE ch.film_id = f.film_id
    )
),
film_popularity AS (
    SELECT
        i.film_id,
        COUNT(r.rental_id) AS rental_count
    FROM rental_copy r
    JOIN inventory i ON r.inventory_id = i.inventory_id
    WHERE r.rental_date >= DATE '2024-01-01'
      AND r.rental_date < DATE '2025-01-01'
    GROUP BY i.film_id
)
SELECT
    cf.film_id,
    cf.title,
    cf.rating,
    c.name AS category,
    cf.category_score,
    COALESCE(fp.rental_count, 0) AS yearly_rentals,
    (cf.category_score * 10 + COALESCE(fp.rental_count, 0)) AS recommendation_score
FROM candidate_films cf
JOIN category c ON cf.category_id = c.category_id
LEFT JOIN film_popularity fp ON cf.film_id = fp.film_id
WHERE cf.rating IN (
    SELECT rating
    FROM customer_history
)
ORDER BY recommendation_score DESC, cf.title
LIMIT 10;

За оптимизираната верзија се користи истата логика, но наместо rental_copy се користи партиционираната табела rental.

Clients Threads rental_copy latency rental_copy stddev rental_copy TPS rental latency rental stddev rental TPS Промена
10 2 2345.556 ms 945.171 ms 4.263 1653.931 ms 549.645 ms 6.046 ~29.5% побрзо
20 4 4820.854 ms 1526.728 ms 4.149 3020.244 ms 889.134 ms 6.622 ~37.4% побрзо
50 4 9811.989 ms 2272.239 ms 5.096 7444.747 ms 1702.896 ms 6.716 ~24.1% побрзо

Q1 покажува подобрување кај оптимизираната табела кај сите нивоа на конкурентност. Кај 10 клиенти латентноста се намалува од 2345.556 ms на 1653.931 ms, а кај 50 клиенти од 9811.989 ms на 7444.747 ms.

Standard deviation исто така е помала кај оптимизираната верзија. Кај 10 клиенти се намалува од 945.171 ms на 549.645 ms, а кај 50 клиенти од 2272.239 ms на 1702.896 ms. Ова покажува дека партиционирањето и индексите не само што го намалуваат просечното време на извршување, туку го прават извршувањето постабилно.

Q2 - Popular Films 2024

Прашалникот ги пресметува најизнајмуваните филмови во 2024 година. Се користи филтер по датум, спојување со inventory и film, групирање по филм и сортирање според бројот на изнајмувања.

SELECT
    f.film_id,
    f.title,
    f.rating,
    COUNT(r.rental_id) AS rental_count
FROM rental_copy r
JOIN inventory i ON r.inventory_id = i.inventory_id
JOIN film f ON i.film_id = f.film_id
WHERE r.rental_date >= DATE '2024-01-01'
  AND r.rental_date < DATE '2025-01-01'
GROUP BY f.film_id, f.title, f.rating
ORDER BY rental_count DESC
LIMIT 20;

За оптимизираната верзија се користи истата логика, но наместо rental_copy се користи партиционираната табела rental.

Clients Threads rental_copy latency rental_copy stddev rental_copy TPS rental latency rental stddev rental TPS Промена
10 4 2183.371 ms 944.412 ms 4.580 1545.473 ms 584.405 ms 6.471 ~29.2% побрзо
20 4 3769.550 ms 1473.425 ms 5.306 3215.116 ms 1297.115 ms 6.221 ~14.7% побрзо
30 4 5653.717 ms 1793.595 ms 5.306 4893.620 ms 1679.520 ms 6.130 ~13.4% побрзо
50 4 10163.130 ms 3034.697 ms 4.920 7924.103 ms 2330.346 ms 6.310 ~22.0% побрзо

Q2 покажува подобри резултати кај партиционираната табела. Латентноста е помала кај сите тестирани нивоа на конкурентност, а TPS е повисок. Standard deviation исто така е помала кај оптимизираната верзија, што покажува постабилно време на извршување. Иако прашалникот содржи GROUP BY и ORDER BY, партиционирањето по rental_date и индексот врз rental_date, inventory_id помагаат затоа што филтерот е ограничен на 2024 година.

Q3 - Monthly Revenue

Прашалникот пресметува месечен приход по продавница за 2024 година. Се пресметуваат број на плаќања, вкупен приход, просечна, минимална и максимална уплата.

SELECT
    date_trunc('month', p.payment_date) AS month,
    s.store_id,
    COUNT(p.payment_id) AS payments_count,
    SUM(p.amount) AS total_revenue,
    AVG(p.amount) AS avg_payment,
    MIN(p.amount) AS min_payment,
    MAX(p.amount) AS max_payment
FROM payment_copy p
JOIN staff s ON p.staff_id = s.staff_id
WHERE p.payment_date >= DATE '2024-01-01'
  AND p.payment_date < DATE '2025-01-01'
GROUP BY date_trunc('month', p.payment_date), s.store_id
ORDER BY month, s.store_id;

За оптимизираната верзија се користи истата логика, но наместо payment_copy се користи партиционираната табела payment.

Clients Threads payment_copy latency payment_copy stddev payment_copy TPS payment latency payment stddev payment TPS Промена
10 4 2806.844 ms 891.434 ms 3.563 1121.703 ms 536.035 ms 8.915 ~60.0% побрзо
30 4 10642.000 ms 5393.351 ms 2.819 3062.069 ms 1034.027 ms 9.797 ~71.2% побрзо
50 4 24061.723 ms 9254.155 ms 2.078 5118.177 ms 1494.030 ms 9.769 ~78.7% побрзо

Q3 има најдобри резултати бидејќи филтерот по payment_date директно го користи партиционирањето на табелата payment. Кај 50 клиенти латентноста се намалува од 24061.723 ms на 5118.177 ms, а TPS се зголемува од 2.078 на 9.769. Standard deviation е значително помала кај партиционираната табела. Кај 50 клиенти се намалува од 9254.155 ms на 1494.030 ms. Ова покажува дека партиционирањето според payment_date значително ја подобрува и брзината и стабилноста на извештајот.

Q4 - INSERT rental

Овој тест мери внесување нови редови во табелата за изнајмувања. За benchmark редовите се користи посебен датум 2026-03-07 12:00:00, за да се разликуваат од оригиналните податоци.

INSERT INTO rental_copy (rental_date, inventory_id, customer_id, staff_id)
VALUES (
    TIMESTAMP '2026-03-07 12:00:00',
    floor(random() * 50000 + 1)::int,
    floor(random() * 1000000 + 1)::int,
    floor(random() * 50 + 1)::int
);

За оптимизираната верзија се користи истата логика, но внесувањето се прави во партиционираната табела rental.

Clients Threads rental_copy latency rental_copy stddev rental_copy TPS rental latency rental stddev rental TPS Промена
10 4 2.750 ms 0.818 ms 3636.964 2.875 ms 0.937 ms 3478.295 ~4.5% побавно
30 4 3.000 ms 1.177 ms 9999.631 3.340 ms 1.557 ms 8981.431 ~11.3% побавно
50 4 7.099 ms 2.297 ms 7043.696 3.501 ms 2.220 ms 14281.463 ~50.7% побрзо

Кај INSERT операциите резултатите се мешани. Кај 10 и 30 клиенти rental_copy има малку подобри резултати, бидејќи кај партиционираната табела PostgreSQL дополнително одредува во која партиција треба да се внесе редот. Кај 50 клиенти партиционираната табела покажува подобар резултат: латентноста се намалува од 7.099 ms на 3.501 ms, а TPS се зголемува од 7043.696 на 14281.463.

Q5 - UPDATE rental

Овој тест мери ажурирање на изнајмувања. Се избира еден ред со benchmark датумот и со return_date IS NULL, па потоа се поставува return_date = now().

UPDATE rental_copy
SET return_date = now()
WHERE rental_id = (
    SELECT rental_id
    FROM rental_copy
    WHERE rental_date = TIMESTAMP '2026-03-07 12:00:00'
      AND return_date IS NULL
    LIMIT 1
);

За оптимизираната верзија се користи истата логика, но ажурирањето се прави врз партиционираната табела rental.

Clients Threads rental_copy latency rental_copy stddev rental_copy TPS rental latency rental stddev rental TPS Промена
10 4 704.821 ms 61.336 ms 14.188 7.093 ms 3.997 ms 1409.861 ~99.0% побрзо
30 4 1923.308 ms 457.842 ms 15.598 26.970 ms 16.112 ms 1112.346 ~98.6% побрзо
50 4 3124.384 ms 700.922 ms 16.003 17.475 ms 13.475 ms 2861.279 ~99.4% побрзо

UPDATE операцијата покажува најголемо подобрување. Кај 10 клиенти латентноста се намалува од 704.821 ms на 7.093 ms, а кај 50 клиенти од 3124.384 ms на 17.475 ms. Standard deviation исто така значително се намалува. Кај 50 клиенти се намалува од 700.922 ms на 13.475 ms. Причината е што UPDATE условот користи конкретен rental_date, па кај партиционираната табела PostgreSQL ја ограничува операцијата на релевантната партиција.

Вкупно подобрување

Партиционираните табели и индексите покажуваат најголемо подобрување кај прашалници кои користат временски филтер врз колоната по која е направено партиционирањето. Освен просечната латентност, во оваа анализа се зема предвид и standard deviation, која покажува колку е стабилно времето на извршување.

Најголеми придобивки:

  • Q3 - Monthly Revenue: најголемо подобрување кај временски ограничените извештаи. Кај 50 клиенти латентноста се намалува од 24061.723 ms на 5118.177 ms, а standard deviation се намалува од 9254.155 ms на 1494.030 ms. Кај 50 клиенти латентноста се намалува од 24061.723 ms на 5118.177 ms, а standard deviation се намалува од 9254.155 ms на 1494.030 ms.
  • Q5 - UPDATE rental: најголемо подобрување кај write операциите. Кај 50 клиенти латентноста се намалува од 3124.384 ms на 17.475 ms, а standard deviation се намалува од 700.922 ms на 13.475 ms.
  • Q1 - Movie Recommendation: има подобрување кај сите нивоа на конкурентност, при што оптимизираната верзија има помала латентност и помала standard deviation.
  • Q2 - Popular Films: по новите мерења со standard deviation, партиционираната табела има подобри резултати кај сите тестирани нивоа на конкурентност.

Мешани резултати:

  • Q4 - INSERT rental: резултатите се мешани. Кај 10 и 30 клиенти rental_copy е малку побрза, затоа што INSERT во партиционирана табела има дополнителен overhead за избор на партиција. Кај 50 клиенти партиционираната табела е подобра, со помала латентност и поголем TPS.

Ова покажува дека оптимизацијата мора да се мери со повеќе метрики. Партиционирањето не е автоматско решение за сите операции, но е многу корисно кога прашалникот користи WHERE услов врз партициската колона, како rental_date или payment_date. Помалата standard deviation кај повеќето оптимизирани тестови покажува и постабилно, попредвидливо извршување.

Операции на читање

  • Q1 - Movie Recommendation: оптимизираната верзија има помала латентност, поголем TPS и помала standard deviation кај сите нивоа на конкурентност.
  • Q2 - Popular Films: по новите мерења, партиционираната табела има подобри резултати кај сите тестирани нивоа на конкурентност. Сепак, прашалникот содржи GROUP BY и ORDER BY, па агрегацијата и сортирањето остануваат значаен дел од трошокот.
  • Q3 - Monthly Revenue: најдобар пример каде партиционирањето директно го намалува бројот на редови што треба да се читаат, бидејќи филтерот користи payment_date, а табелата payment е партиционирана според истата колона.

Кај операциите на читање, најдобри резултати се добиваат кога WHERE условот ја користи колоната по која е направено партиционирањето. Дополнително, помалата standard deviation кај оптимизираните верзии покажува дека извршувањето е постабилно и попредвидливо.

Операции на запишување

  • INSERT: резултатите се мешани. Кај 10 и 30 клиенти rental_copy е малку побрза, но кај 50 клиенти партиционираната табела има подобра латентност и повисок TPS.
  • UPDATE: има многу големо подобрување кај партиционираната табела, затоа што условот користи конкретна вредност за rental_date.

Кај INSERT, партиционирањето може да додаде overhead затоа што PostgreSQL мора да одреди во која партиција треба да се внесе новиот ред. Кај UPDATE, партиционирањето е многу корисно кога условот ја користи партициската колона, бидејќи пребарувањето се ограничува на релевантната партиција наместо на целата табела.

Заклучок

За ова специфично работно оптоварување:

  • Партиционирањето е многу корисно за временски извештаи, особено кај payment и rental.
  • Индексите значително помагаат кај прашалници со WHERE услови и JOIN операции врз често користени колони.
  • Q3 и Q5 покажуваат најголемо подобрување, затоа што директно ја користат колоната по која е направено партиционирањето.
  • Q1 и Q2 покажуваат подобрување кај SELECT прашалници кои користат временски филтри, но кај Q2 агрегацијата и сортирањето остануваат значаен дел од трошокот.
  • INSERT операциите треба да се мерат внимателно, бидејќи партиционирањето може да додаде overhead при внесување, особено при помал број клиенти.
  • Standard deviation е важна метрика затоа што покажува колку се стабилни перформансите. Кај повеќето оптимизирани тестови standard deviation е помала, што значи дека времето на извршување е попредвидливо.

Најсоодветен пристап за оваа база е да се задржи партиционирањето по датум за големите трансакциски табели rental и payment, да се користат индекси само за најчестите филтри и спојувања, и редовно да се проверуваат резултатите со EXPLAIN ANALYZE и pgbench.

Note: See TracWiki for help on using the wiki.