Оптимизација на прашалници
Овој поглед дава преглед на сите изведувачи и настаните на кои тие учествуваат, заедно со прецизниот термин на нивниот настап.
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;
Без индекс:
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 | `
|
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
|
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);
Со индекс:
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
|
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
|
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;
Без индекс:
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
|
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
|
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);
Со индекс:
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
|
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
|
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;
Без индекс:
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
|
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
|
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);
Со индекс:
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
|
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
|
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;
Без индекс:
EXPLAIN ANALYZE
SELECT * FROM "Event_User_Ratings"
WHERE user_id = 1;
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";
EXPLAIN ANALYZE
UPDATE "Event_Happening_Rating"
SET rating = 4, comment = 'New test rating'
WHERE event_happening_id = 1 AND user_id = 1;
Без индекси, секое пребарување на оценките по корисник предизвикува непотребно оптоварување на меморијата преку 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);
Со индекс:
EXPLAIN ANALYZE
SELECT * FROM "Event_User_Ratings" WHERE user_id = 1;
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";
EXPLAIN ANALYZE
UPDATE "Event_Happening_Rating"
SET rating = 6, comment = 'New test rating'
WHERE event_happening_id = 1 AND user_id = 2;
Анализа и оптимизација на 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;
Без индекс:
EXPLAIN ANALYZE
SELECT * FROM "Event_Overall_Ratings" WHERE event_id = 1;
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";
EXPLAIN ANALYZE
UPDATE "Event_Happening_Rating"
SET rating = 8, comment = 'New test rating'
WHERE event_happening_id = 1 AND user_id = 15;
Пресметката на просечни оценки бара постојано агрегирање на податоци, што е бавно при секој нов приказ. Композитен индекс на (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);
Со индекс:
EXPLAIN ANALYZE
SELECT * FROM "Event_Overall_Ratings" WHERE event_id = 1;
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";
EXPLAIN ANALYZE
UPDATE "Event_Happening_Rating"
SET rating = 8, comment = 'New test rating'
WHERE event_happening_id = 1 AND user_id = 15;
Анализа и оптимизација на 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;
Без индекс:
EXPLAIN ANALYZE
SELECT * FROM "Event_Financial_Summary" WHERE event_id = 1;
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";
EXPLAIN ANALYZE
UPDATE "Ticket_Purchase"
SET purchase_amount = 1800.00
WHERE qr_code = 'QR-TEST-CODE-003';
Овој поглед има критично време на извршување од над 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);
Со индекс:
EXPLAIN ANALYZE
SELECT * FROM "Event_Financial_Summary" WHERE event_id = 1;
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";
EXPLAIN ANALYZE
UPDATE "Ticket_Purchase"
SET purchase_amount = 1700.00
WHERE qr_code = 'QR-TEST-CODE-004';
Анализа и оптимизација на 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;
Без индекс:
EXPLAIN ANALYZE
SELECT * FROM "Future_Events"
WHERE venue_id = 1;
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);
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);
Со индекс:
EXPLAIN ANALYZE
SELECT * FROM "Future_Events"
WHERE venue_id = 1;
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);
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;
Без индекс:
EXPLAIN ANALYZE
SELECT * FROM "Available_Tickets"
WHERE event_id = 1;
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);
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);
Со индекс:
EXPLAIN ANALYZE
SELECT * FROM "Available_Tickets"
WHERE event_id = 1;
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);
EXPLAIN ANALYZE
UPDATE "Ticket"
SET base_price = 700.00
WHERE ticket_id = (SELECT MAX(ticket_id) FROM "Ticket");