wiki:QueryOptimization

Version 56 (modified by 231027, 2 weeks ago) ( diff )

--

Оптимизација на прашалници

Анализа и оптимизација на Performer_Events

Овој поглед дава преглед на сите изведувачи и настаните на кои тие учествуваат, заедно со прецизниот термин на нивниот настап.

CREATE VIEW "Performer_Events" AS
SELECT p.performer_id,
       p.name AS performer_name,
       e.event_id,
       e.name AS event_name,
       eh.event_time
FROM "Performer" p
JOIN "Event_Happening_Performer" ehp ON p.performer_id = ehp.performer_id
JOIN "Event_Happening" eh ON ehp.event_happening_id = eh.event_happening_id
JOIN "Event" e ON eh.event_id = e.event_id;

Без индекс:

  • SELECT
EXPLAIN ANALYZE
    SELECT * FROM "Performer_Events" WHERE performer_id = 10;

QUERY PLAN
Nested Loop (cost\=1.14..73.38 rows\=7 width\=68) (actual time\=1505.862..3249.242 rows\=4 loops\=1)
-> Nested Loop (cost\=0.86..70.92 rows\=7 width\=37) (actual time\=1079.648..2259.465 rows\=4 loops\=1)
-> Index Scan using "Performer_pkey" on "Performer" p (cost\=0.28..8.30 rows\=1 width\=21) (actual time\=701.003..701.005 rows\=1 loops\=1)
Index Cond: (performer_id \= 10)
-> Nested Loop (cost\=0.57..62.55 rows\=7 width\=24) (actual time\=378.637..1558.442 rows\=4 loops\=1)
-> Index Only Scan using uq_performer_at_time on "Event_Happening_Performer" ehp (cost\=0.29..4.41 rows\=7 width\=16) (actual time\=90.817..90.838 rows\=4 loops\=1)
Index Cond: (performer_id \= 10)
Heap Fetches: 0
-> Index Scan using "Event_Happening_pkey" on "Event_Happening" eh (cost\=0.29..8.30 rows\=1 width\=24) (actual time\=366.888..366.889 rows\=1 loops\=4)
Index Cond: (event_happening_id \= ehp.event_happening_id)
-> Index Scan using "Event_pkey" on "Event" e (cost\=0.29..0.35 rows\=1 width\=39) (actual time\=247.432..247.432 rows\=1 loops\=4)
Index Cond: (event_id \= eh.event_id)
Planning Time: 1816.633 ms
Execution Time: 3249.314 ms
  • INSERT
EXPLAIN ANALYZE
    INSERT INTO "Event_Happening_Performer" (event_happening_id, performer_id)
    VALUES (1, 10);

QUERY PLAN
Insert on "Event_Happening_Performer" (cost\=0.00..0.01 rows\=0 width\=0) (actual time\=558.243..558.244 rows\=0 loops\=1)
-> Result (cost\=0.00..0.01 rows\=1 width\=16) (actual time\=0.001..0.002 rows\=1 loops\=1)
Planning Time: 0.042 ms
Trigger for constraint fk_ehp_event_happening: time\=826.105 calls\=1
Trigger for constraint fk_ehp_performer: time\=40.075 calls\=1
Execution Time: 1424.451 ms
  • UPDATE
EXPLAIN ANALYZE
    UPDATE "Event_Happening_Performer"
    SET performer_id = 11
    WHERE event_happening_id = 1 AND performer_id = 10;

QUERY PLAN
Update on "Event_Happening_Performer" (cost\=0.29..8.31 rows\=0 width\=0) (actual time\=0.219..0.219 rows\=0 loops\=1)
-> Index Scan using uq_performer_at_time on "Event_Happening_Performer" (cost\=0.29..8.31 rows\=1 width\=14) (actual time\=0.120..0.121 rows\=1 loops\=1)
Index Cond: ((performer_id \= 10) AND (event_happening_id \= 1))
Planning Time: 0.139 ms
Trigger for constraint fk_ehp_performer: time\=0.279 calls\=1
Execution Time: 23.621 ms

Погледот е бавен поради комплексни врски помеѓи четири табели што резултира со време од 3.2s. Индексите на performer_id и event_id го елиминираат целосното скенирање на табелите и овозможуваат инстантно поврзување на изведувачите со нивните настани.

Оптимизација:

-- indexes for linking performers with specific event occurrences (M:N relationship)
CREATE INDEX idx_ehp_performer_id ON "Event_Happening_Performer"(performer_id);
CREATE INDEX idx_ehp_happening_id ON "Event_Happening_Performer"(event_happening_id);

-- index for optimizing event lookups within scheduled event happenings
CREATE INDEX idx_event_happening_event_id ON "Event_Happening"(event_id);

Со индекс:

  • SELECT
EXPLAIN ANALYZE
    SELECT * FROM "Performer_Events" WHERE performer_id = 10;

QUERY PLAN
Nested Loop (cost\=1.14..77.38 rows\=7 width\=68) (actual time\=0.251..0.479 rows\=4 loops\=1)
-> Nested Loop (cost\=0.86..74.92 rows\=7 width\=37) (actual time\=0.201..0.306 rows\=4 loops\=1)
-> Index Scan using "Performer_pkey" on "Performer" p (cost\=0.28..8.30 rows\=1 width\=21) (actual time\=0.093..0.094 rows\=1 loops\=1)
Index Cond: (performer_id \= 10)
-> Nested Loop (cost\=0.57..66.55 rows\=7 width\=24) (actual time\=0.105..0.207 rows\=4 loops\=1)
-> Index Only Scan using uq_performer_at_time on "Event_Happening_Performer" ehp (cost\=0.29..8.41 rows\=7 width\=16) (actual time\=0.062..0.065 rows\=4 loops\=1)
Index Cond: (performer_id \= 10)
Heap Fetches: 1
-> Index Scan using "Event_Happening_pkey" on "Event_Happening" eh (cost\=0.29..8.30 rows\=1 width\=24) (actual time\=0.032..0.032 rows\=1 loops\=4)
Index Cond: (event_happening_id \= ehp.event_happening_id)
-> Index Scan using "Event_pkey" on "Event" e (cost\=0.29..0.35 rows\=1 width\=39) (actual time\=0.041..0.041 rows\=1 loops\=4)
Index Cond: (event_id \= eh.event_id)
Planning Time: 1.600 ms
Execution Time: 0.533 ms
  • INSERT
EXPLAIN ANALYZE
    INSERT INTO "Event_Happening_Performer" (event_happening_id, performer_id)
    VALUES (2, 10);

QUERY PLAN
Insert on "Event_Happening_Performer" (cost\=0.00..0.01 rows\=0 width\=0) (actual time\=0.307..0.308 rows\=0 loops\=1)
-> Result (cost\=0.00..0.01 rows\=1 width\=16) (actual time\=0.001..0.001 rows\=1 loops\=1)
Planning Time: 0.046 ms
Trigger for constraint fk_ehp_event_happening: time\=0.332 calls\=1
Trigger for constraint fk_ehp_performer: time\=0.169 calls\=1
Execution Time: 0.833 ms
  • UPDATE
EXPLAIN ANALYZE
    UPDATE "Event_Happening_Performer"
    SET performer_id = 12
    WHERE event_happening_id = 2 AND performer_id = 10;

QUERY PLAN
Update on "Event_Happening_Performer" (cost\=0.29..8.31 rows\=0 width\=0) (actual time\=0.437..0.438 rows\=0 loops\=1)
-> Index Scan using idx_ehp_happening_id on "Event_Happening_Performer" (cost\=0.29..8.31 rows\=1 width\=14) (actual time\=0.174..0.175 rows\=1 loops\=1)
Index Cond: (event_happening_id \= 2)
Filter: (performer_id \= 10)
Rows Removed by Filter: 1
Planning Time: 0.161 ms
Trigger for constraint fk_ehp_performer: time\=0.271 calls\=1
Execution Time: 0.763 ms

Анализа и оптимизација на Venue_Layout

Овој поглед ја прикажува целосната структура на секој објект (сала), поврзувајќи ги поединечните седишта со соодветните сектори и името на објектот.

CREATE VIEW "Venue_Layout" AS
SELECT v.venue_id,
       v.name AS venue_name,
       s.section_id,
       s.name AS section_name,
       st.seat_id,
       st.seat_number
FROM "Venue" v
JOIN "Section" s ON v.venue_id = s.venue_id
JOIN "Seat" st ON s.section_id = st.section_id;

Без индекс:

  • SELECT
EXPLAIN ANALYZE
    SELECT * FROM "Venue_Layout" WHERE venue_id = 1;

QUERY PLAN
Nested Loop (cost\=1001.14..10398.19 rows\=2264 width\=55) (actual time\=447.576..2164.258 rows\=775 loops\=1)
-> Index Scan using "Venue_pkey" on "Venue" v (cost\=0.29..8.30 rows\=1 width\=28) (actual time\=68.551..68.555 rows\=1 loops\=1)
Index Cond: (venue_id \= 1)
-> Gather (cost\=1000.85..10367.25 rows\=2264 width\=35) (actual time\=379.017..2095.610 rows\=775 loops\=1)
Workers Planned: 1
Workers Launched: 1
-> Nested Loop (cost\=0.85..9140.85 rows\=1332 width\=35) (actual time\=932.279..1787.769 rows\=388 loops\=2)
-> Parallel Index Scan using "Section_pkey" on "Section" s (cost\=0.29..1691.80 rows\=4 width\=23) (actual time\=771.383..1395.534 rows\=2 loops\=2)
Filter: (venue_id \= 1)
Rows Removed by Filter: 27502
-> Index Scan using uq_seat_section_number on "Seat" st (cost\=0.56..1853.21 rows\=905 width\=20) (actual time\=64.373..156.866 rows\=155 loops\=5)
Index Cond: (section_id \= s.section_id)
Planning Time: 1874.048 ms
Execution Time: 2164.361 ms
  • INSERT
EXPLAIN ANALYZE
    INSERT INTO "Seat" (seat_id, section_id, seat_number)
    SELECT COALESCE(MAX(seat_id), 0) + 1, 1, 999999 FROM "Seat";

QUERY PLAN
Insert on "Seat" (cost\=0.67..0.69 rows\=0 width\=0) (actual time\=745.461..745.464 rows\=0 loops\=1)
-> Subquery Scan on "*SELECT*" (cost\=0.67..0.69 rows\=1 width\=20) (actual time\=481.921..481.925 rows\=1 loops\=1)
-> Result (cost\=0.67..0.69 rows\=1 width\=16) (actual time\=481.918..481.920 rows\=1 loops\=1)
InitPlan 1
-> Limit (cost\=0.56..0.67 rows\=1 width\=8) (actual time\=481.909..481.910 rows\=1 loops\=1)
-> Index Only Scan Backward using "Seat_pkey" on "Seat" "Seat_1" (cost\=0.56..2330912.81 rows\=20753208 width\=8) (actual time\=481.907..481.908 rows\=1 loops\=1)
Heap Fetches: 0
Planning Time: 0.339 ms
Trigger for constraint fk_seat_section: time\=0.533 calls\=1
Execution Time: 746.039 ms
  • UPDATE
EXPLAIN ANALYZE
    UPDATE "Seat"
    SET seat_number = 888888
    WHERE seat_number = 999999;

QUERY PLAN
Update on "Seat" (cost\=0.00..391602.10 rows\=0 width\=0) (actual time\=308799.033..308799.035 rows\=0 loops\=1)
-> Seq Scan on "Seat" (cost\=0.00..391602.10 rows\=11492 width\=10) (actual time\=308792.032..308792.034 rows\=1 loops\=1)
Filter: (seat_number \= 999999)
Rows Removed by Filter: 20753209
Planning Time: 0.114 ms
JIT:
Functions: 4
Options: Inlining false, Optimization false, Expressions true, Deforming true
Timing: Generation 0.405 ms (Deform 0.071 ms), Inlining 0.000 ms, Optimization 0.595 ms, Emission 6.566 ms, Total 7.565 ms
Execution Time: 312239.424 ms

Времето за ажурирање од 312s е неприфатливо за интеракција со мапа на седишта во реално време. Со поставување индекси на seat_number и venue_id, пребарувањето и промената на статусот на седиштата се извршуваат за милисекунди наместо за неколку минути.

Оптимизација:

-- index for linking seats to their respective sections
CREATE INDEX idx_seat_section_id ON "Seat"(section_id);

-- index for linking sections to venues
CREATE INDEX idx_section_venue_id ON "Section"(venue_id);

-- index for optimizing search and update operations on specific seat numbers
CREATE INDEX idx_seat_number ON "Seat"(seat_number);

Со индекс:

  • SELECT
EXPLAIN ANALYZE
    SELECT * FROM "Venue_Layout" WHERE venue_id = 1;

QUERY PLAN
Nested Loop (cost\=1.01..3060.48 rows\=2264 width\=55) (actual time\=0.184..0.512 rows\=776 loops\=1)
-> Nested Loop (cost\=0.57..16.76 rows\=6 width\=43) (actual time\=0.140..0.144 rows\=5 loops\=1)
-> Index Scan using "Venue_pkey" on "Venue" v (cost\=0.29..8.30 rows\=1 width\=28) (actual time\=0.077..0.078 rows\=1 loops\=1)
Index Cond: (venue_id \= 1)
-> Index Scan using idx_section_venue_id on "Section" s (cost\=0.29..8.39 rows\=6 width\=23) (actual time\=0.058..0.060 rows\=5 loops\=1)
Index Cond: (venue_id \= 1)
-> Index Scan using idx_seat_section_id on "Seat" st (cost\=0.44..498.24 rows\=905 width\=20) (actual time\=0.012..0.053 rows\=155 loops\=5)
Index Cond: (section_id \= s.section_id)
Planning Time: 1.235 ms
Execution Time: 0.572 ms
  • INSERT
EXPLAIN ANALYZE
    INSERT INTO "Seat" (seat_id, section_id, seat_number)
    SELECT COALESCE(MAX(seat_id), 0) + 1, 1, 111222 FROM "Seat";

QUERY PLAN
Insert on "Seat" (cost\=0.67..0.69 rows\=0 width\=0) (actual time\=0.493..0.494 rows\=0 loops\=1)
-> Subquery Scan on "*SELECT*" (cost\=0.67..0.69 rows\=1 width\=20) (actual time\=0.169..0.171 rows\=1 loops\=1)
-> Result (cost\=0.67..0.69 rows\=1 width\=16) (actual time\=0.167..0.168 rows\=1 loops\=1)
InitPlan 1
-> Limit (cost\=0.56..0.67 rows\=1 width\=8) (actual time\=0.162..0.163 rows\=1 loops\=1)
-> Index Only Scan Backward using "Seat_pkey" on "Seat" "Seat_1" (cost\=0.56..2330912.84 rows\=20753210 width\=8) (actual time\=0.161..0.161 rows\=1 loops\=1)
Heap Fetches: 1
Planning Time: 0.219 ms
Trigger for constraint fk_seat_section: time\=0.300 calls\=1
Execution Time: 0.839 ms
  • UPDATE
EXPLAIN ANALYZE
    UPDATE "Seat"
    SET seat_number = 333444
    WHERE seat_number = 111222;

QUERY PLAN
Update on "Seat" (cost\=0.44..44297.09 rows\=0 width\=0) (actual time\=0.395..0.396 rows\=0 loops\=1)
-> Index Scan using idx_seat_number on "Seat" (cost\=0.44..44297.09 rows\=11492 width\=10) (actual time\=0.193..0.195 rows\=1 loops\=1)
Index Cond: (seat_number \= 111222)
Planning Time: 0.141 ms
Execution Time: 0.461 ms

Анализа и оптимизација на User_Tickets

Овој поглед ја прикажува целосната структура на секој објект (сала), поврзувајќи ги поединечните седишта со соодветните сектори и името на објектот.

CREATE VIEW "User_Tickets" AS
SELECT u.user_id,
       u.username,
       t.ticket_id,
       e.event_id,
       e.name AS event_name,
       tp.purchase_id,
       tp.qr_code,
       tr.refund_id,
       tr.refund_time
FROM "User" u
JOIN "Ticket_Purchase" tp ON u.user_id = tp.user_id
JOIN "Ticket" t ON tp.ticket_id = t.ticket_id
JOIN "Event_Happening" eh ON t.event_happening_id = eh.event_happening_id
JOIN "Event" e ON eh.event_id = e.event_id
LEFT JOIN "Ticket_Refund" tr ON tp.purchase_id = tr.purchase_id;

Без индекс:

  • SELECT
EXPLAIN ANALYZE
    SELECT * FROM "User_Tickets" WHERE user_id = 1;

QUERY PLAN
Nested Loop Left Join (cost\=1002.00..232798.26 rows\=1 width\=115) (actual time\=431.345..441.975 rows\=1 loops\=1)
-> Nested Loop (cost\=1001.56..232789.81 rows\=1 width\=99) (actual time\=431.312..441.941 rows\=1 loops\=1)
-> Nested Loop (cost\=1001.28..232789.45 rows\=1 width\=68) (actual time\=431.253..441.878 rows\=1 loops\=1)
-> Nested Loop (cost\=1000.99..232789.15 rows\=1 width\=68) (actual time\=431.200..441.822 rows\=1 loops\=1)
-> Nested Loop (cost\=1000.43..232780.57 rows\=1 width\=60) (actual time\=431.038..441.657 rows\=1 loops\=1)
-> Index Scan using "User_pkey" on "User" u (cost\=0.43..8.45 rows\=1 width\=26) (actual time\=0.114..0.118 rows\=1 loops\=1)
Index Cond: (user_id \= 1)
-> Gather (cost\=1000.00..232772.11 rows\=1 width\=42) (actual time\=430.826..441.440 rows\=1 loops\=1)
Workers Planned: 4
Workers Launched: 4
-> Parallel Seq Scan on "Ticket_Purchase" tp (cost\=0.00..231772.01 rows\=1 width\=42) (actual time\=389.356..389.357 rows\=0 loops\=5)
Filter: (user_id \= 1)
Rows Removed by Filter: 3200000
-> Index Scan using "Ticket_pkey" on "Ticket" t (cost\=0.56..8.58 rows\=1 width\=16) (actual time\=0.104..0.105 rows\=1 loops\=1)
Index Cond: (ticket_id \= tp.ticket_id)
-> Index Scan using "Event_Happening_pkey" on "Event_Happening" eh (cost\=0.29..0.31 rows\=1 width\=16) (actual time\=0.033..0.034 rows\=1 loops\=1)
Index Cond: (event_happening_id \= t.event_happening_id)
-> Index Scan using "Event_pkey" on "Event" e (cost\=0.29..0.35 rows\=1 width\=39) (actual time\=0.039..0.040 rows\=1 loops\=1)
Index Cond: (event_id \= eh.event_id)
-> Index Scan using "Ticket_Refund_purchase_id_key" on "Ticket_Refund" tr (cost\=0.43..8.45 rows\=1 width\=24) (actual time\=0.015..0.016 rows\=0 loops\=1)
Index Cond: (purchase_id \= tp.purchase_id)
Planning Time: 15.360 ms
JIT:
Functions: 44
Options: Inlining false, Optimization false, Expressions true, Deforming true
Timing: Generation 3.367 ms (Deform 1.376 ms), Inlining 0.000 ms, Optimization 2.363 ms, Emission 42.753 ms, Total 48.484 ms
Execution Time: 443.784 ms
  • INSERT
EXPLAIN ANALYZE
    INSERT INTO "Ticket_Purchase" (purchase_id, ticket_id, user_id, qr_code, purchase_amount)
    SELECT COALESCE(MAX(purchase_id), 0) + 1, 1, 1, 'QR-TEST-CODE-001', 1200.00
    FROM "Ticket_Purchase";

QUERY PLAN
Insert on "Ticket_Purchase" (cost\=0.47..0.50 rows\=0 width\=0) (actual time\=0.217..0.218 rows\=0 loops\=1)
-> Subquery Scan on "*SELECT*" (cost\=0.47..0.50 rows\=1 width\=552) (actual time\=0.055..0.057 rows\=1 loops\=1)
-> Result (cost\=0.47..0.48 rows\=1 width\=80) (actual time\=0.043..0.044 rows\=1 loops\=1)
InitPlan 1
-> Limit (cost\=0.43..0.47 rows\=1 width\=8) (actual time\=0.038..0.039 rows\=1 loops\=1)
-> Index Only Scan Backward using "Ticket_Purchase_pkey" on "Ticket_Purchase" "Ticket_Purchase_1" (cost\=0.43..484152.95 rows\=16000004 width\=8) (actual time\=0.037..0.038 rows\=1 loops\=1)
Heap Fetches: 3
Planning Time: 0.207 ms
Trigger for constraint fk_purchase_ticket: time\=0.190 calls\=1
Trigger for constraint fk_purchase_user: time\=0.136 calls\=1
Execution Time: 0.600 ms
  • UPDATE
EXPLAIN ANALYZE
    UPDATE "Ticket_Purchase"
    SET purchase_amount = 1500.00
    WHERE user_id = 1 AND qr_code = 'QR-TEST-CODE-001';

QUERY PLAN
Update on "Ticket_Purchase" (cost\=0.56..8.58 rows\=0 width\=0) (actual time\=0.121..0.122 rows\=0 loops\=1)
-> Index Scan using "Ticket_Purchase_qr_code_key" on "Ticket_Purchase" (cost\=0.56..8.58 rows\=1 width\=10) (actual time\=0.048..0.050 rows\=1 loops\=1)
Index Cond: ((qr_code)::text \= 'QR-TEST-CODE-001'::text)
Filter: (user_id \= 1)
Planning Time: 0.181 ms
Execution Time: 0.157 ms

Приказот на историјата на билети трае предолги 251.9s, што го блокира корисничкиот профил. Индексот на user_id овозможува базата веднаш да ги лоцира билетите на конкретниот корисник без да ги пребарува сите трансакции во системот.

Оптимизација:

-- index for linking ticket purchases to the specific tickets
CREATE INDEX idx_ticket_purchase_ticket_id ON "Ticket_Purchase"(ticket_id);

-- index for linking purchases to users
CREATE INDEX idx_ticket_purchase_user_id ON "Ticket_Purchase"(user_id);

-- index for the LEFT JOIN with refunds
CREATE INDEX idx_ticket_refund_purchase_id ON "Ticket_Refund"(purchase_id);

-- index for optimizing event lookups within scheduled event happenings
CREATE INDEX idx_event_happening_event_id ON "Event_Happening"(event_id);

Со индекс:

  • SELECT
EXPLAIN ANALYZE
    SELECT * FROM "User_Tickets" WHERE user_id = 1;

QUERY PLAN
Nested Loop Left Join (cost\=1002.00..232798.25 rows\=1 width\=115) (actual time\=438.622..449.169 rows\=2 loops\=1)
-> Nested Loop (cost\=1001.56..232789.80 rows\=1 width\=99) (actual time\=438.588..449.128 rows\=2 loops\=1)
-> Gather (cost\=1001.13..232781.35 rows\=1 width\=81) (actual time\=438.383..448.900 rows\=2 loops\=1)
Workers Planned: 4
Workers Launched: 4
-> Nested Loop (cost\=1.14..231781.25 rows\=1 width\=81) (actual time\=397.225..397.235 rows\=0 loops\=5)
-> Nested Loop (cost\=0.85..231780.89 rows\=1 width\=50) (actual time\=397.203..397.211 rows\=0 loops\=5)
-> Nested Loop (cost\=0.56..231780.59 rows\=1 width\=50) (actual time\=397.176..397.182 rows\=0 loops\=5)
-> Parallel Seq Scan on "Ticket_Purchase" tp (cost\=0.00..231772.01 rows\=1 width\=42) (actual time\=397.114..397.115 rows\=0 loops\=5)
Filter: (user_id \= 1)
Rows Removed by Filter: 3200000
-> Index Scan using "Ticket_pkey" on "Ticket" t (cost\=0.56..8.58 rows\=1 width\=16) (actual time\=0.107..0.107 rows\=1 loops\=2)
Index Cond: (ticket_id \= tp.ticket_id)
-> Index Scan using "Event_Happening_pkey" on "Event_Happening" eh (cost\=0.29..0.31 rows\=1 width\=16) (actual time\=0.055..0.055 rows\=1 loops\=2)
Index Cond: (event_happening_id \= t.event_happening_id)
-> Index Scan using "Event_pkey" on "Event" e (cost\=0.29..0.35 rows\=1 width\=39) (actual time\=0.044..0.044 rows\=1 loops\=2)
Index Cond: (event_id \= eh.event_id)
-> Index Scan using "User_pkey" on "User" u (cost\=0.43..8.45 rows\=1 width\=26) (actual time\=0.086..0.087 rows\=1 loops\=2)
Index Cond: (user_id \= 1)
-> Index Scan using idx_ticket_refund_purchase_id on "Ticket_Refund" tr (cost\=0.43..8.45 rows\=1 width\=24) (actual time\=0.010..0.010 rows\=0 loops\=2)
Index Cond: (purchase_id \= tp.purchase_id)
Planning Time: 2.459 ms
JIT:
Functions: 99
Options: Inlining false, Optimization false, Expressions true, Deforming true
Timing: Generation 7.544 ms (Deform 3.336 ms), Inlining 0.000 ms, Optimization 3.874 ms, Emission 71.829 ms, Total 83.247 ms
Execution Time: 450.880 ms
  • INSERT
EXPLAIN ANALYZE
    INSERT INTO "Ticket_Purchase" (purchase_id, ticket_id, user_id, qr_code, purchase_amount)
    SELECT COALESCE(MAX(purchase_id), 0) + 1, 1, 1, 'QR-TEST-CODE-002', 1200.00
    FROM "Ticket_Purchase";

QUERY PLAN
Insert on "Ticket_Purchase" (cost\=0.47..0.50 rows\=0 width\=0) (actual time\=0.452..0.453 rows\=0 loops\=1)
-> Subquery Scan on "*SELECT*" (cost\=0.47..0.50 rows\=1 width\=552) (actual time\=0.049..0.051 rows\=1 loops\=1)
-> Result (cost\=0.47..0.48 rows\=1 width\=80) (actual time\=0.038..0.039 rows\=1 loops\=1)
InitPlan 1
-> Limit (cost\=0.43..0.47 rows\=1 width\=8) (actual time\=0.033..0.033 rows\=1 loops\=1)
-> Index Only Scan Backward using "Ticket_Purchase_pkey" on "Ticket_Purchase" "Ticket_Purchase_1" (cost\=0.43..484152.93 rows\=16000003 width\=8) (actual time\=0.032..0.032 rows\=1 loops\=1)
Heap Fetches: 2
Planning Time: 0.207 ms
Trigger for constraint fk_purchase_ticket: time\=0.194 calls\=1
Trigger for constraint fk_purchase_user: time\=0.130 calls\=1
Execution Time: 0.828 ms
  • UPDATE
EXPLAIN ANALYZE
    UPDATE "Ticket_Purchase"
    SET purchase_amount = 1350.00
    WHERE user_id = 1 AND qr_code = 'QR-TEST-CODE-002';

QUERY PLAN
Update on "Ticket_Purchase" (cost\=0.56..8.58 rows\=0 width\=0) (actual time\=0.207..0.207 rows\=0 loops\=1)
-> Index Scan using "Ticket_Purchase_qr_code_key" on "Ticket_Purchase" (cost\=0.56..8.58 rows\=1 width\=10) (actual time\=0.124..0.126 rows\=1 loops\=1)
Index Cond: ((qr_code)::text \= 'QR-TEST-CODE-002'::text)
Filter: (user_id \= 1)
Planning Time: 0.150 ms
Execution Time: 0.267 ms

Анализа и оптимизација на Event_User_Ratings

Овој поглед овозможува детален пристап до поединечните коментари и оценки што секој корисник ги оставил за одреден термин на настан.

CREATE VIEW "Event_User_Ratings" AS
SELECT eh.event_happening_id,
       e.event_id,
       e.name AS event_name,
       u.user_id,
       u.username,
       ehr.rating_id,
       ehr.rating,
       ehr.comment
FROM "Event" e
JOIN "Event_Happening" eh ON e.event_id = eh.event_id
JOIN "Event_Happening_Rating" ehr ON eh.event_happening_id = ehr.event_happening_id
JOIN "User" u ON ehr.user_id = u.user_id;

Без индекс:

  • SELECT
EXPLAIN ANALYZE
    SELECT * FROM "Event_User_Ratings"
    WHERE user_id = 1;

QUERY PLAN
Nested Loop (cost\=1.29..21.42 rows\=1 width\=131) (actual time\=0.104..0.105 rows\=0 loops\=1)
-> Nested Loop (cost\=0.86..12.96 rows\=1 width\=113) (actual time\=0.103..0.105 rows\=0 loops\=1)
-> Nested Loop (cost\=0.57..12.61 rows\=1 width\=82) (actual time\=0.103..0.104 rows\=0 loops\=1)
-> Index Scan using idx_ehr_user_id on "Event_Happening_Rating" ehr (cost\=0.29..4.30 rows\=1 width\=74) (actual time\=0.103..0.103 rows\=0 loops\=1)
Index Cond: (user_id \= 1)
-> Index Scan using "Event_Happening_pkey" on "Event_Happening" eh (cost\=0.29..8.30 rows\=1 width\=16) (never executed)
Index Cond: (event_happening_id \= ehr.event_happening_id)
-> Index Scan using "Event_pkey" on "Event" e (cost\=0.29..0.35 rows\=1 width\=39) (never executed)
Index Cond: (event_id \= eh.event_id)
-> Index Scan using "User_pkey" on "User" u (cost\=0.43..8.45 rows\=1 width\=26) (never executed)
Index Cond: (user_id \= 1)
Planning Time: 464.594 ms
Execution Time: 0.187 ms
  • INSERT
EXPLAIN ANALYZE
    INSERT INTO "Event_Happening_Rating" (rating_id, event_happening_id, user_id, rating, comment)
    SELECT COALESCE(MAX(rating_id), 0) + 1, 1, 1, 5, 'Test rating'
    FROM "Event_Happening_Rating";

QUERY PLAN
Insert on "Event_Happening_Rating" (cost\=0.31..0.34 rows\=0 width\=0) (actual time\=0.521..0.522 rows\=0 loops\=1)
-> Subquery Scan on "*SELECT*" (cost\=0.31..0.34 rows\=1 width\=60) (actual time\=0.122..0.123 rows\=1 loops\=1)
-> Result (cost\=0.31..0.33 rows\=1 width\=52) (actual time\=0.119..0.120 rows\=1 loops\=1)
InitPlan 1
-> Limit (cost\=0.29..0.31 rows\=1 width\=8) (actual time\=0.114..0.115 rows\=1 loops\=1)
-> Index Only Scan Backward using "Event_Happening_Rating_pkey" on "Event_Happening_Rating" "Event_Happening_Rating_1" (cost\=0.29..478.37 rows\=17872 width\=8) (actual time\=0.113..0.113 rows\=1 loops\=1)
Heap Fetches: 6
Planning Time: 0.297 ms
Trigger for constraint fk_event_happening_rating_event_happening: time\=0.490 calls\=1
Trigger for constraint fk_event_happening_rating_user: time\=0.370 calls\=1
Execution Time: 1.444 ms
  • UPDATE
EXPLAIN ANALYZE
    UPDATE "Event_Happening_Rating"
    SET rating = 4, comment = 'New test rating'
    WHERE event_happening_id = 1 AND user_id = 1;

QUERY PLAN
Update on "Event_Happening_Rating" (cost\=0.29..4.31 rows\=0 width\=0) (actual time\=0.176..0.177 rows\=0 loops\=1)
-> Index Scan using idx_ehr_user_id on "Event_Happening_Rating" (cost\=0.29..4.31 rows\=1 width\=42) (actual time\=0.039..0.042 rows\=1 loops\=1)
Index Cond: (user_id \= 1)
Filter: (event_happening_id \= 1)
Planning Time: 0.153 ms
Execution Time: 0.218 ms

Без индекси, секое пребарување на оценките по корисник предизвикува непотребно оптоварување на меморијата преку Seq Scan. Индексирањето на user_id и event_happening_id обезбедува брза филтрација и поврзување на рејтинзите со соодветните термини на настаните.

Оптимизација:

-- index for linking ratings to event happenings
CREATE INDEX idx_ehr_happening_id ON "Event_Happening_Rating"(event_happening_id);

-- index for linking ratings to users
CREATE INDEX idx_ehr_user_id ON "Event_Happening_Rating"(user_id);

Со индекс:

  • SELECT
EXPLAIN ANALYZE
    SELECT * FROM "Event_User_Ratings" WHERE user_id = 1;

QUERY PLAN
Nested Loop (cost\=1.00..476.51 rows\=1 width\=131) (actual time\=359.514..359.524 rows\=1 loops\=1)
-> Nested Loop (cost\=0.57..468.06 rows\=1 width\=113) (actual time\=359.389..359.396 rows\=1 loops\=1)
-> Nested Loop (cost\=0.29..467.71 rows\=1 width\=82) (actual time\=2.104..2.110 rows\=1 loops\=1)
-> Seq Scan on "Event_Happening_Rating" ehr (cost\=0.00..459.40 rows\=1 width\=74) (actual time\=2.038..2.041 rows\=1 loops\=1)
Filter: (user_id \= 1)
Rows Removed by Filter: 17871
-> Index Scan using "Event_Happening_pkey" on "Event_Happening" eh (cost\=0.29..8.30 rows\=1 width\=16) (actual time\=0.061..0.062 rows\=1 loops\=1)
Index Cond: (event_happening_id \= ehr.event_happening_id)
-> Index Scan using "Event_pkey" on "Event" e (cost\=0.29..0.35 rows\=1 width\=39) (actual time\=357.279..357.280 rows\=1 loops\=1)
Index Cond: (event_id \= eh.event_id)
-> Index Scan using "User_pkey" on "User" u (cost\=0.43..8.45 rows\=1 width\=26) (actual time\=0.120..0.121 rows\=1 loops\=1)
Index Cond: (user_id \= 1)
Planning Time: 31.049 ms
Execution Time: 359.600 ms
  • INSERT
EXPLAIN ANALYZE
    INSERT INTO "Event_Happening_Rating" (rating_id, event_happening_id, user_id, rating, comment)
    SELECT COALESCE(MAX(rating_id), 0) + 1, 2, 1, 5, 'Test rating'
    FROM "Event_Happening_Rating";

QUERY PLAN
Insert on "Event_Happening_Rating" (cost\=0.31..0.34 rows\=0 width\=0) (actual time\=0.482..0.483 rows\=0 loops\=1)
-> Subquery Scan on "*SELECT*" (cost\=0.31..0.34 rows\=1 width\=60) (actual time\=0.117..0.119 rows\=1 loops\=1)
-> Result (cost\=0.31..0.33 rows\=1 width\=52) (actual time\=0.115..0.115 rows\=1 loops\=1)
InitPlan 1
-> Limit (cost\=0.29..0.31 rows\=1 width\=8) (actual time\=0.110..0.111 rows\=1 loops\=1)
-> Index Only Scan Backward using "Event_Happening_Rating_pkey" on "Event_Happening_Rating" "Event_Happening_Rating_1" (cost\=0.29..484.37 rows\=17872 width\=8) (actual time\=0.108..0.108 rows\=1 loops\=1)
Heap Fetches: 4
Planning Time: 0.203 ms
Trigger for constraint fk_event_happening_rating_event_happening: time\=0.197 calls\=1
Trigger for constraint fk_event_happening_rating_user: time\=0.114 calls\=1
Execution Time: 0.842 ms
  • UPDATE
EXPLAIN ANALYZE
    UPDATE "Event_Happening_Rating"
    SET rating = 6, comment = 'New test rating'
    WHERE event_happening_id = 1 AND user_id = 2;

QUERY PLAN
Update on "Event_Happening_Rating" (cost\=0.29..8.31 rows\=0 width\=0) (actual time\=0.021..0.022 rows\=0 loops\=1)
-> Index Scan using uq_rating_happening_user on "Event_Happening_Rating" (cost\=0.29..8.31 rows\=1 width\=42) (actual time\=0.020..0.021 rows\=0 loops\=1)
Index Cond: ((event_happening_id \= 1) AND (user_id \= 2))
Planning Time: 0.132 ms
Execution Time: 0.081 ms

Анализа и оптимизација на Event_Overall_Ratings

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

CREATE VIEW "Event_Overall_Ratings" AS
SELECT 
    e.event_id,
    e.name AS event_name,
    eh.event_happening_id,
    eh.event_time,
    COUNT(ehr.rating_id) AS total_reviews,
    AVG(ehr.rating) AS average_rating
FROM "Event" e
JOIN "Event_Happening" eh ON e.event_id = eh.event_id
JOIN "Event_Happening_Rating" ehr ON eh.event_happening_id = ehr.event_happening_id
GROUP BY e.event_id, e.name, eh.event_happening_id, eh.event_time;

Без индекс:

  • SELECT
EXPLAIN ANALYZE
    SELECT * FROM "Event_Overall_Ratings" WHERE event_id = 1;

QUERY PLAN
GroupAggregate (cost\=72.25..72.32 rows\=3 width\=95) (actual time\=1029.642..1029.647 rows\=1 loops\=1)
Group Key: eh.event_happening_id
-> Sort (cost\=72.25..72.26 rows\=3 width\=67) (actual time\=1029.557..1029.604 rows\=1 loops\=1)
Sort Key: eh.event_happening_id
Sort Method: quicksort Memory: 25kB
-> Nested Loop (cost\=4.90..72.22 rows\=3 width\=67) (actual time\=223.616..1029.548 rows\=1 loops\=1)
-> Index Scan using "Event_pkey" on "Event" e (cost\=0.29..8.30 rows\=1 width\=39) (actual time\=0.046..0.053 rows\=1 loops\=1)
Index Cond: (event_id \= 1)
-> Nested Loop (cost\=4.61..63.89 rows\=3 width\=36) (actual time\=223.566..1029.488 rows\=1 loops\=1)
-> Bitmap Heap Scan on "Event_Happening" eh (cost\=4.33..22.32 rows\=5 width\=24) (actual time\=0.054..805.890 rows\=5 loops\=1)
Recheck Cond: (event_id \= 1)
Heap Blocks: exact\=5
-> Bitmap Index Scan on idx_event_happening_event_id (cost\=0.00..4.32 rows\=5 width\=0) (actual time\=0.029..0.029 rows\=5 loops\=1)
Index Cond: (event_id \= 1)
-> Index Scan using uq_rating_happening_user on "Event_Happening_Rating" ehr (cost\=0.29..8.30 rows\=1 width\=20) (actual time\=44.710..44.711 rows\=0 loops\=5)
Index Cond: (event_happening_id \= eh.event_happening_id)
Planning Time: 1.025 ms
Execution Time: 1029.756 ms
  • INSERT
EXPLAIN ANALYZE
    INSERT INTO "Event_Happening_Rating" (rating_id, event_happening_id, user_id, rating, comment)
    SELECT COALESCE(MAX(rating_id), 0) + 1, 1, 15, 9, 'Test rating'
    FROM "Event_Happening_Rating";

QUERY PLAN
Insert on "Event_Happening_Rating" (cost\=0.31..0.34 rows\=0 width\=0) (actual time\=0.405..0.407 rows\=0 loops\=1)
-> Subquery Scan on "*SELECT*" (cost\=0.31..0.34 rows\=1 width\=60) (actual time\=0.156..0.158 rows\=1 loops\=1)
-> Result (cost\=0.31..0.33 rows\=1 width\=52) (actual time\=0.154..0.155 rows\=1 loops\=1)
InitPlan 1
-> Limit (cost\=0.29..0.31 rows\=1 width\=8) (actual time\=0.149..0.149 rows\=1 loops\=1)
-> Index Only Scan Backward using "Event_Happening_Rating_pkey" on "Event_Happening_Rating" "Event_Happening_Rating_1" (cost\=0.29..484.37 rows\=17872 width\=8) (actual time\=0.148..0.148 rows\=1 loops\=1)
Heap Fetches: 2
Planning Time: 0.199 ms
Trigger for constraint fk_event_happening_rating_event_happening: time\=0.232 calls\=1
Trigger for constraint fk_event_happening_rating_user: time\=0.234 calls\=1
Execution Time: 0.918 ms
  • UPDATE
EXPLAIN ANALYZE
    UPDATE "Event_Happening_Rating"
    SET rating = 8, comment = 'New test rating'
    WHERE event_happening_id = 1 AND user_id = 15;

QUERY PLAN
Update on "Event_Happening_Rating" (cost\=0.29..8.31 rows\=0 width\=0) (actual time\=0.458..0.459 rows\=0 loops\=1)
-> Index Scan using uq_rating_happening_user on "Event_Happening_Rating" (cost\=0.29..8.31 rows\=1 width\=42) (actual time\=0.131..0.133 rows\=1 loops\=1)
Index Cond: ((event_happening_id \= 1) AND (user_id \= 15))
Planning Time: 0.136 ms
Execution Time: 0.500 ms

Пресметката на просечни оценки бара постојано агрегирање на податоци, што е бавно при секој нов приказ. Композитен индекс на (event_happening_id, rating) овозможува математичките операции да се вршат директно врз индексот, забрзувајќи го приказот на почетната страна.

Оптимизација:

-- composite index to speed up grouping and aggregate calculations (AVG, COUNT)
CREATE INDEX idx_ehr_happening_id_rating ON "Event_Happening_Rating"(event_happening_id, rating);

Со индекс:

  • SELECT
EXPLAIN ANALYZE
    SELECT * FROM "Event_Overall_Ratings" WHERE event_id = 1;

QUERY PLAN
GroupAggregate (cost\=72.25..72.32 rows\=3 width\=95) (actual time\=0.387..0.389 rows\=1 loops\=1)
Group Key: eh.event_happening_id
-> Sort (cost\=72.25..72.26 rows\=3 width\=67) (actual time\=0.374..0.375 rows\=1 loops\=1)
Sort Key: eh.event_happening_id
Sort Method: quicksort Memory: 25kB
-> Nested Loop (cost\=4.90..72.22 rows\=3 width\=67) (actual time\=0.271..0.367 rows\=1 loops\=1)
-> Index Scan using "Event_pkey" on "Event" e (cost\=0.29..8.30 rows\=1 width\=39) (actual time\=0.126..0.128 rows\=1 loops\=1)
Index Cond: (event_id \= 1)
-> Nested Loop (cost\=4.61..63.89 rows\=3 width\=36) (actual time\=0.142..0.235 rows\=1 loops\=1)
-> Bitmap Heap Scan on "Event_Happening" eh (cost\=4.33..22.32 rows\=5 width\=24) (actual time\=0.067..0.144 rows\=5 loops\=1)
Recheck Cond: (event_id \= 1)
Heap Blocks: exact\=5
-> Bitmap Index Scan on idx_event_happening_event_id (cost\=0.00..4.32 rows\=5 width\=0) (actual time\=0.038..0.038 rows\=5 loops\=1)
Index Cond: (event_id \= 1)
-> Index Scan using uq_rating_happening_user on "Event_Happening_Rating" ehr (cost\=0.29..8.30 rows\=1 width\=20) (actual time\=0.016..0.016 rows\=0 loops\=5)
Index Cond: (event_happening_id \= eh.event_happening_id)
Planning Time: 1.134 ms
Execution Time: 0.459 ms
  • INSERT
EXPLAIN ANALYZE
    INSERT INTO "Event_Happening_Rating" (rating_id, event_happening_id, user_id, rating, comment)
    SELECT COALESCE(MAX(rating_id), 0) + 1, 1, 20, 7, 'Test rating'
    FROM "Event_Happening_Rating";

QUERY PLAN
Insert on "Event_Happening_Rating" (cost\=0.31..0.34 rows\=0 width\=0) (actual time\=0.538..0.539 rows\=0 loops\=1)
-> Subquery Scan on "*SELECT*" (cost\=0.31..0.34 rows\=1 width\=60) (actual time\=0.111..0.112 rows\=1 loops\=1)
-> Result (cost\=0.31..0.33 rows\=1 width\=52) (actual time\=0.109..0.109 rows\=1 loops\=1)
InitPlan 1
-> Limit (cost\=0.29..0.31 rows\=1 width\=8) (actual time\=0.104..0.105 rows\=1 loops\=1)
-> Index Only Scan Backward using "Event_Happening_Rating_pkey" on "Event_Happening_Rating" "Event_Happening_Rating_1" (cost\=0.29..485.40 rows\=17874 width\=8) (actual time\=0.102..0.103 rows\=1 loops\=1)
Heap Fetches: 1
Planning Time: 0.195 ms
Trigger for constraint fk_event_happening_rating_event_happening: time\=0.223 calls\=1
Trigger for constraint fk_event_happening_rating_user: time\=0.172 calls\=1
Execution Time: 0.980 ms
  • UPDATE
EXPLAIN ANALYZE
    UPDATE "Event_Happening_Rating"
    SET rating = 8, comment = 'New test rating'
    WHERE event_happening_id = 1 AND user_id = 15;

QUERY PLAN
Update on "Event_Happening_Rating" (cost\=0.29..8.31 rows\=0 width\=0) (actual time\=0.482..0.483 rows\=0 loops\=1)
-> Index Scan using uq_rating_happening_user on "Event_Happening_Rating" (cost\=0.29..8.31 rows\=1 width\=42) (actual time\=0.096..0.098 rows\=1 loops\=1)
Index Cond: ((event_happening_id \= 1) AND (user_id \= 20))
Planning Time: 0.163 ms
Execution Time: 0.548 ms

Анализа и оптимизација на Event_Financial_Summary

Овој поглед ги сумира финансиските резултати за секој настан, прикажувајќи го вкупниот број на продадени билети, нето приходот по одбивање на рефундациите и посебно издвоената заработка од административните такси при враќање на влезниците.

CREATE VIEW "Event_Financial_Summary" AS
SELECT 
    e.event_id,
    e.name AS event_name,
    eh.event_happening_id,
    eh.event_time,
    COUNT(tp.purchase_id) AS total_tickets_sold,
    
    -- total revenue
    SUM(tp.purchase_amount) - SUM(CASE WHEN tr.refund_amount IS NOT NULL THEN tr.refund_amount ELSE 0 END) AS net_revenue,
    
    -- refund taxes
    SUM(CASE WHEN tr.refund_id IS NOT NULL THEN tp.purchase_amount - tr.refund_amount ELSE 0 END) AS refund_tax_profit

FROM "Event" e
JOIN "Event_Happening" eh ON e.event_id = eh.event_id
JOIN "Ticket" t ON eh.event_happening_id = t.event_happening_id
JOIN "Ticket_Purchase" tp ON t.ticket_id = tp.ticket_id
LEFT JOIN "Ticket_Refund" tr ON tp.purchase_id = tr.purchase_id
GROUP BY e.event_id, e.name, eh.event_happening_id, eh.event_time;

Без индекс:

  • SELECT
EXPLAIN ANALYZE
    SELECT * FROM "Event_Financial_Summary" WHERE event_id = 1;

QUERY PLAN
Finalize GroupAggregate (cost\=300491.02..300511.03 rows\=5 width\=71) (actual time\=319308.288..319318.376 rows\=1 loops\=1)
Group Key: eh.event_happening_id
-> Gather Merge (cost\=300491.02..300510.84 rows\=10 width\=75) (actual time\=319308.204..319318.298 rows\=1 loops\=1)
Workers Planned: 2
Workers Launched: 2
-> Partial GroupAggregate (cost\=299491.00..299509.67 rows\=5 width\=75) (actual time\=319135.885..319135.894 rows\=0 loops\=3)
Group Key: eh.event_happening_id
-> Sort (cost\=299491.00..299493.66 rows\=1064 width\=79) (actual time\=319135.736..319135.767 rows\=388 loops\=3)
Sort Key: eh.event_happening_id
Sort Method: quicksort Memory: 25kB
Worker 0: Sort Method: quicksort Memory: 25kB
Worker 1: Sort Method: quicksort Memory: 160kB
-> Nested Loop Left Join (cost\=17569.44..299437.50 rows\=1064 width\=79) (actual time\=257215.363..319135.341 rows\=388 loops\=3)
-> Parallel Hash Join (cost\=17569.00..291013.94 rows\=1064 width\=67) (actual time\=257187.356..319052.018 rows\=388 loops\=3)
Hash Cond: (tp.ticket_id \= t.ticket_id)
-> Parallel Seq Scan on "Ticket_Purchase" tp (cost\=0.00..248438.67 rows\=6666668 width\=20) (actual time\=39.675..315154.157 rows\=5333334 loops\=3)
-> Parallel Hash (cost\=17536.03..17536.03 rows\=2638 width\=63) (actual time\=2787.389..2787.393 rows\=1442 loops\=3)
Buckets: 8192 Batches: 1 Memory Usage: 576kB
-> Nested Loop (cost\=1.14..17536.03 rows\=2638 width\=63) (actual time\=1483.997..2465.151 rows\=1442 loops\=3)
-> Nested Loop (cost\=0.57..1029.33 rows\=3 width\=55) (actual time\=632.603..753.210 rows\=2 loops\=3)
-> Parallel Index Scan using "Event_Happening_pkey" on "Event_Happening" eh (cost\=0.29..1004.39 rows\=3 width\=24) (actual time\=632.410..752.992 rows\=2 loops\=3)
Filter: (event_id \= 1)
Rows Removed by Filter: 10444
-> Index Scan using "Event_pkey" on "Event" e (cost\=0.29..8.30 rows\=1 width\=39) (actual time\=0.094..0.100 rows\=1 loops\=5)
Index Cond: (event_id \= 1)
-> Index Scan using uq_ticket_event_happening_seat on "Ticket" t (cost\=0.56..5486.81 rows\=1542 width\=16) (actual time\=652.636..1027.008 rows\=865 loops\=5)
Index Cond: (event_happening_id \= eh.event_happening_id)
-> Index Scan using idx_ticket_refund_purchase_id on "Ticket_Refund" tr (cost\=0.43..7.92 rows\=1 width\=20) (actual time\=0.214..0.214 rows\=0 loops\=1163)
Index Cond: (purchase_id \= tp.purchase_id)
Planning Time: 2770.897 ms
JIT:
Functions: 96
Options: Inlining false, Optimization false, Expressions true, Deforming true
Timing: Generation 9.017 ms (Deform 4.245 ms), Inlining 0.000 ms, Optimization 4.730 ms, Emission 79.393 ms, Total 93.140 ms
Execution Time: 319320.792 ms
  • INSERT
EXPLAIN ANALYZE
    INSERT INTO "Ticket_Purchase" (purchase_id, ticket_id, user_id, qr_code, purchase_time, purchase_amount)
    SELECT COALESCE(MAX(purchase_id), 0) + 1, 1, 1, 'QR-TEST-CODE-003', CURRENT_TIMESTAMP, 1500.00
    FROM "Ticket_Purchase";

QUERY PLAN
Insert on "Ticket_Purchase" (cost\=0.70..0.73 rows\=0 width\=0) (actual time\=1391.459..1391.461 rows\=0 loops\=1)
-> Subquery Scan on "*SELECT*" (cost\=0.70..0.73 rows\=1 width\=552) (actual time\=0.132..0.137 rows\=1 loops\=1)
-> Result (cost\=0.70..0.71 rows\=1 width\=88) (actual time\=0.106..0.109 rows\=1 loops\=1)
InitPlan 1
-> Limit (cost\=0.43..0.70 rows\=1 width\=8) (actual time\=0.101..0.102 rows\=1 loops\=1)
-> Index Only Scan Backward using "Ticket_Purchase_pkey" on "Ticket_Purchase" "Ticket_Purchase_1" (cost\=0.43..4162966.51 rows\=16000002 width\=8) (actual time\=0.099..0.099 rows\=1 loops\=1)
Heap Fetches: 1
Planning Time: 0.232 ms
Trigger for constraint fk_purchase_ticket: time\=1.278 calls\=1
Trigger for constraint fk_purchase_user: time\=0.358 calls\=1
Execution Time: 1393.154 ms
  • UPDATE
EXPLAIN ANALYZE
    UPDATE "Ticket_Purchase"
    SET purchase_amount = 1800.00
    WHERE qr_code = 'QR-TEST-CODE-003';

QUERY PLAN
Update on "Ticket_Purchase" (cost\=0.56..8.58 rows\=0 width\=0) (actual time\=0.266..0.267 rows\=0 loops\=1)
-> Index Scan using "Ticket_Purchase_qr_code_key" on "Ticket_Purchase" (cost\=0.56..8.58 rows\=1 width\=10) (actual time\=0.117..0.119 rows\=1 loops\=1)
Index Cond: ((qr_code)::text \= 'QR-TEST-CODE-003'::text)
Planning Time: 0.188 ms
Execution Time: 0.364 ms

Овој поглед има критично време на извршување од над 5 минути поради обработка на милиони трансакции. Индексите на ticket_id го намалуваат времето за 99%, овозможувајќи моментален преглед на приходите и рефундациите за секој настан.

Оптимизација:

-- index for linking ticket purchases to the specific tickets
CREATE INDEX idx_ticket_purchase_ticket_id ON "Ticket_Purchase"(ticket_id);

-- index for the LEFT JOIN with refunds to calculate net revenue accurately
CREATE INDEX idx_ticket_refund_purchase_id ON "Ticket_Refund"(purchase_id);

-- index for linking tickets to scheduled events
CREATE INDEX idx_ticket_event_happening_id ON "Ticket"(event_happening_id);

Со индекс:

  • SELECT
EXPLAIN ANALYZE
    SELECT * FROM "Event_Financial_Summary" WHERE event_id = 1;

QUERY PLAN
Finalize GroupAggregate (cost\=298955.06..298975.08 rows\=5 width\=71) (actual time\=1499.323..1508.016 rows\=1 loops\=1)
Group Key: eh.event_happening_id
-> Gather Merge (cost\=298955.06..298974.89 rows\=10 width\=75) (actual time\=1499.269..1507.962 rows\=1 loops\=1)
Workers Planned: 2
Workers Launched: 2
-> Partial GroupAggregate (cost\=297955.04..297973.71 rows\=5 width\=75) (actual time\=1463.528..1463.535 rows\=0 loops\=3)
Group Key: eh.event_happening_id
-> Sort (cost\=297955.04..297957.70 rows\=1064 width\=79) (actual time\=1463.377..1463.407 rows\=388 loops\=3)
Sort Key: eh.event_happening_id
Sort Method: quicksort Memory: 25kB
Worker 0: Sort Method: quicksort Memory: 25kB
Worker 1: Sort Method: quicksort Memory: 160kB
-> Nested Loop Left Join (cost\=16033.48..297901.55 rows\=1064 width\=79) (actual time\=1201.975..1463.060 rows\=388 loops\=3)
-> Parallel Hash Join (cost\=16033.05..289477.99 rows\=1064 width\=67) (actual time\=1201.913..1460.100 rows\=388 loops\=3)
Hash Cond: (tp.ticket_id \= t.ticket_id)
-> Parallel Seq Scan on "Ticket_Purchase" tp (cost\=0.00..248438.67 rows\=6666668 width\=20) (actual time\=0.091..663.287 rows\=5333334 loops\=3)
-> Parallel Hash (cost\=16000.08..16000.08 rows\=2638 width\=63) (actual time\=13.806..13.809 rows\=1442 loops\=3)
Buckets: 8192 Batches: 1 Memory Usage: 512kB
-> Nested Loop (cost\=1.01..16000.08 rows\=2638 width\=63) (actual time\=30.720..39.526 rows\=4325 loops\=1)
-> Nested Loop (cost\=0.57..1029.33 rows\=3 width\=55) (actual time\=30.641..37.392 rows\=5 loops\=1)
-> Parallel Index Scan using "Event_Happening_pkey" on "Event_Happening" eh (cost\=0.29..1004.39 rows\=3 width\=24) (actual time\=30.536..37.242 rows\=5 loops\=1)
Filter: (event_id \= 1)
Rows Removed by Filter: 31332
-> Index Scan using "Event_pkey" on "Event" e (cost\=0.29..8.30 rows\=1 width\=39) (actual time\=0.021..0.023 rows\=1 loops\=5)
Index Cond: (event_id \= 1)
-> Index Scan using idx_ticket_event_happening_id on "Ticket" t (cost\=0.44..4974.83 rows\=1542 width\=16) (actual time\=0.052..0.324 rows\=865 loops\=5)
Index Cond: (event_happening_id \= eh.event_happening_id)
-> Index Scan using idx_ticket_refund_purchase_id on "Ticket_Refund" tr (cost\=0.43..7.92 rows\=1 width\=20) (actual time\=0.007..0.007 rows\=0 loops\=1163)
Index Cond: (purchase_id \= tp.purchase_id)
Planning Time: 1.604 ms
JIT:
Functions: 96
Options: Inlining false, Optimization false, Expressions true, Deforming true
Timing: Generation 8.629 ms (Deform 3.959 ms), Inlining 0.000 ms, Optimization 3.603 ms, Emission 79.354 ms, Total 91.585 ms
Execution Time: 1510.555 ms
  • INSERT
EXPLAIN ANALYZE
    INSERT INTO "Ticket_Purchase" (purchase_id, ticket_id, user_id, qr_code, purchase_time, purchase_amount)
    SELECT COALESCE(MAX(purchase_id), 0) + 1, 1, 2, 'QR-TEST-CODE-004', CURRENT_TIMESTAMP, 1400.00
    FROM "Ticket_Purchase";

QUERY PLAN
Insert on "Ticket_Purchase" (cost\=0.70..0.73 rows\=0 width\=0) (actual time\=0.351..0.352 rows\=0 loops\=1)
-> Subquery Scan on "*SELECT*" (cost\=0.70..0.73 rows\=1 width\=552) (actual time\=0.145..0.147 rows\=1 loops\=1)
-> Result (cost\=0.70..0.71 rows\=1 width\=88) (actual time\=0.132..0.133 rows\=1 loops\=1)
InitPlan 1
-> Limit (cost\=0.43..0.70 rows\=1 width\=8) (actual time\=0.126..0.127 rows\=1 loops\=1)
-> Index Only Scan Backward using "Ticket_Purchase_pkey" on "Ticket_Purchase" "Ticket_Purchase_1" (cost\=0.43..4162966.51 rows\=16000002 width\=8) (actual time\=0.124..0.124 rows\=1 loops\=1)
Heap Fetches: 2
Planning Time: 0.208 ms
Trigger for constraint fk_purchase_ticket: time\=0.225 calls\=1
Trigger for constraint fk_purchase_user: time\=0.176 calls\=1
Execution Time: 0.802 ms
  • UPDATE
EXPLAIN ANALYZE
    UPDATE "Ticket_Purchase"
    SET purchase_amount = 1700.00
    WHERE qr_code = 'QR-TEST-CODE-004';

QUERY PLAN
Update on "Ticket_Purchase" (cost\=0.56..8.58 rows\=0 width\=0) (actual time\=0.161..0.162 rows\=0 loops\=1)
-> Index Scan using "Ticket_Purchase_qr_code_key" on "Ticket_Purchase" (cost\=0.56..8.58 rows\=1 width\=10) (actual time\=0.115..0.116 rows\=1 loops\=1)
Index Cond: ((qr_code)::text \= 'QR-TEST-CODE-004'::text)
Planning Time: 0.134 ms
Execution Time: 0.195 ms

Анализа и оптимизација на Future_Events

Овој поглед служи за динамично генерирање на репертоарот, прикажувајќи ги исклучиво претстојните настани во реално време преку филтрирање на изминатите термини.

CREATE VIEW "Future_Events" AS
SELECT
    e.event_id,
    e.name AS event_name,
    eh.event_happening_id,
    eh.event_time,
    v.venue_id,
    v.name AS venue_name,
    v.address_city AS city
FROM "Event" e
JOIN "Event_Happening" eh ON e.event_id = eh.event_id
JOIN "Venue" v ON eh.venue_id = v.venue_id
WHERE eh.event_time > CURRENT_TIMESTAMP;

Без индекс:

  • SELECT
EXPLAIN ANALYZE
    SELECT * FROM "Future_Events"
    WHERE venue_id = 1;

  • INSERT
EXPLAIN ANALYZE
    INSERT INTO "Event_Happening" (event_happening_id, event_id, venue_id, event_time, duration)
    VALUES ((SELECT MAX(event_happening_id) + 1 FROM "Event_Happening"), 1, 1, '2026-12-31 20:00:00', 120);

  • UPDATE
EXPLAIN ANALYZE
    UPDATE "Event_Happening"
    SET event_time = '2027-01-01 21:00:00'
    WHERE event_happening_id = (SELECT MAX(event_happening_id) FROM "Event_Happening");

Времето на извршување е релативно ниско, но базата троши 4.258 ms само на планирање на секој поединечен запис. Бидејќи редовите не се подредени по време, системот мора да врши постојани споредби за секој настан. Заради ова, потребен е индекс кој ќе овозможи моментално лоцирање на идните настани без пребарување на целата табела.

Оптимизација:

-- index for optimizing chronological filtering of future events
CREATE INDEX idx_event_happening_time ON "Event_Happening"(event_time);

-- index for accelerating lookups of events scheduled at specific venues
CREATE INDEX idx_event_happening_venue_id ON "Event_Happening"(venue_id);

-- composite index to optimize queries filtering both by venue and upcoming time slots
CREATE INDEX idx_event_happening_venue_time ON "Event_Happening"(venue_id, event_time);

Со индекс:

  • SELECT
EXPLAIN ANALYZE
    SELECT * FROM "Future_Events"
    WHERE venue_id = 1;

  • INSERT
EXPLAIN ANALYZE
    INSERT INTO "Event_Happening" (event_happening_id, event_id, venue_id, event_time, duration)
    VALUES ((SELECT MAX(event_happening_id) + 1 FROM "Event_Happening"), 1, 1, '2026-11-15 19:00:00', 90);

  • UPDATE
EXPLAIN ANALYZE
    UPDATE "Event_Happening"
    SET event_time = '2026-11-20 20:00:00'
    WHERE event_happening_id = (SELECT MAX(event_happening_id) FROM "Event_Happening");

Анализа и оптимизација на Available_Tickets

Овој поглед овозможува моментален увид во инвентарот на достапни седишта и автоматско враќање на рефундираните билети во понуда.

CREATE VIEW "Available_Tickets" AS
SELECT
    t.ticket_id,
    t.ticket_type,
    t.base_price,
    e.event_id,
    e.name AS event_name,
    eh.event_happening_id,
    eh.event_time,
    s.name AS section_name,
    st.seat_number
FROM "Ticket" t
JOIN "Event_Happening" eh ON t.event_happening_id = eh.event_happening_id
JOIN "Event" e ON eh.event_id = e.event_id
JOIN "Seat" st ON t.seat_id = st.seat_id
JOIN "Section" s ON st.section_id = s.section_id
WHERE t.is_available = TRUE;

Без индекс:

  • SELECT
EXPLAIN ANALYZE
    SELECT * FROM "Available_Tickets"
    WHERE event_id = 1;

  • INSERT
EXPLAIN ANALYZE
    INSERT INTO "Ticket" (ticket_id, ticket_type, base_price, is_available, event_happening_id, seat_id)
    VALUES ((SELECT MAX(ticket_id) + 1 FROM "Ticket"), 'Standard', 500.00, TRUE, 1, 999999);

  • UPDATE
EXPLAIN ANALYZE
    UPDATE "Ticket"
    SET base_price = 600.00
    WHERE ticket_id = (SELECT MAX(ticket_id) FROM "Ticket");

За овој поглед се трошат 948.13 ms бидејќи базата мора да пребарува низ 30 милиони записи. Овој процес вклучува скапи операции со трошок од 27455.75, каде се читаат милиони непотребни записи од дискот. Заради ова, потребен е индекс кој ќе ги издвои само достапните билети и ќе го елиминира ваквото чекање.

Оптимизација:

-- partial index for rapid retrieval of only unsold tickets by filtering out sold ones
CREATE INDEX idx_ticket_is_available_true ON "Ticket"(is_available) WHERE is_available = TRUE;

-- index for linking tickets to scheduled events to accelerate event-based filtering
CREATE INDEX idx_ticket_event_happening_id ON "Ticket"(event_happening_id);

-- index for optimizing seat-based joins to retrieve venue layout details for each ticket
CREATE INDEX idx_ticket_seat_id ON "Ticket"(seat_id);

Со индекс:

  • SELECT
EXPLAIN ANALYZE
    SELECT * FROM "Available_Tickets"
    WHERE event_id = 1;

  • INSERT
EXPLAIN ANALYZE 
    INSERT INTO "Ticket" (ticket_id, ticket_type, base_price, is_available, event_happening_id, seat_id)
    VALUES ((SELECT MAX(ticket_id) + 1 FROM "Ticket"), 'Standard', 500.00, TRUE, 1, 888888);

  • UPDATE
EXPLAIN ANALYZE
    UPDATE "Ticket"
    SET base_price = 700.00
    WHERE ticket_id = (SELECT MAX(ticket_id) FROM "Ticket");

Note: See TracWiki for help on using the wiki.