| | 320 | === p_event_risk_overview === |
| | 321 | {{{ |
| | 322 | CREATE OR REPLACE PROCEDURE p_event_risk_overview( |
| | 323 | IN p_event_id int, |
| | 324 | IN p_actor_id int, |
| | 325 | IN p_user_id int, |
| | 326 | IN p_from_date date DEFAULT NULL, |
| | 327 | IN p_to_date date DEFAULT NULL, |
| | 328 | INOUT p_cur refcursor DEFAULT NULL |
| | 329 | ) |
| | 330 | LANGUAGE plpgsql |
| | 331 | AS $$ |
| | 332 | BEGIN |
| | 333 | IF p_cur IS NULL THEN p_cur := 'cur_event_risk_overview'; END IF; |
| | 334 | |
| | 335 | OPEN p_cur FOR |
| | 336 | WITH |
| | 337 | -- Кој актер и која локација се поврзани со настанот |
| | 338 | event_context AS ( |
| | 339 | SELECT ed.global_event_id, ed.actor_id, ed.location_id |
| | 340 | FROM event_details ed |
| | 341 | WHERE ed.global_event_id = p_event_id |
| | 342 | OR ed.actor_id = p_actor_id |
| | 343 | ), |
| | 344 | -- Нотификации поврзани со корисник или настан |
| | 345 | notif AS ( |
| | 346 | SELECT n.notification_id, n.user_id, n.notification_date, n.event_id |
| | 347 | FROM notifications n |
| | 348 | WHERE (n.user_id = p_user_id AND n.notification_date BETWEEN COALESCE(p_from_date,'1900-01-01') AND COALESCE(p_to_date, now()::date)) |
| | 349 | OR (n.event_id = p_event_id) |
| | 350 | ), |
| | 351 | -- Прогнози поврзани со настанот/актерот |
| | 352 | preds AS ( |
| | 353 | SELECT pr.prediction_id, pr.event_id, pr.actor_id, pr.predicted_date, pr.confidence |
| | 354 | FROM predictions pr |
| | 355 | WHERE pr.event_id = p_event_id |
| | 356 | OR pr.actor_id = p_actor_id |
| | 357 | ), |
| | 358 | -- Аналитика за настан + актер по датуми |
| | 359 | analytics AS ( |
| | 360 | SELECT ea.event_id, ea.actor_id, ea.date, ea.metric_value |
| | 361 | FROM event_analytics ea |
| | 362 | WHERE ea.event_id = p_event_id |
| | 363 | AND ea.actor_id = p_actor_id |
| | 364 | AND ea.date BETWEEN COALESCE(p_from_date,'1900-01-01') AND COALESCE(p_to_date, now()::date) |
| | 365 | ), |
| | 366 | -- Ризици помеѓу парови актери |
| | 367 | risks AS ( |
| | 368 | SELECT cr.actor1_id, cr.actor2_id, cr.predicted_date, cr.risk_score |
| | 369 | FROM conflict_risk cr |
| | 370 | WHERE (cr.actor1_id = p_actor_id OR cr.actor2_id = p_actor_id) |
| | 371 | AND cr.predicted_date BETWEEN COALESCE(p_from_date,'1900-01-01') AND COALESCE(p_to_date, now()::date) |
| | 372 | ) |
| | 373 | SELECT jsonb_build_object( |
| | 374 | 'event_id', p_event_id, |
| | 375 | 'actor_id', p_actor_id, |
| | 376 | 'notifications', COALESCE(jsonb_agg(DISTINCT notif), '[]'::jsonb), |
| | 377 | 'predictions', COALESCE(jsonb_agg(DISTINCT preds), '[]'::jsonb), |
| | 378 | 'analytics', COALESCE(jsonb_agg(DISTINCT analytics), '[]'::jsonb), |
| | 379 | 'risks', COALESCE(jsonb_agg(DISTINCT risks), '[]'::jsonb) |
| | 380 | ) AS j |
| | 381 | FROM notif, preds, analytics, risks; |
| | 382 | END; |
| | 383 | $$; |
| | 384 | }}} |
| | 385 | |
| | 386 | == Објаснување на Execution Plan == |
| | 387 | |
| | 388 | При повик на `p_event_risk_overview` со `EXPLAIN (ANALYZE, BUFFERS)`, PostgreSQL користи индекс скенирања за оптимален пристап: |
| | 389 | |
| | 390 | * **event_details** → `Index Scan` на `ix_event_details_event` или `ix_event_details_actor` за брзо наоѓање актери/локации поврзани со настанот. |
| | 391 | * **notifications** → `Index Scan` на `ix_notifications_user` (композитен индекс по user/date) или `ix_notifications_event` за пребарување на кориснички нотификации. |
| | 392 | * **predictions** → `Index Scan` на `ix_predictions_event` или `ix_predictions_actor` за селекција на предвидувања. |
| | 393 | * **event_analytics** → `Index Scan` на `ix_analytics_event_actor` со дополнително филтрирање по `date`. |
| | 394 | * **conflict_risk** → `Index Scan` на `ix_conflict_pair_date` за проверка на ризици меѓу актери во даден временски интервал. |
| | 395 | |
| | 396 | Ова покажува дека секоја табела се пристапува преку соодветен индекс наместо со целосно скенирање, |
| | 397 | што значително ја зголемува брзината и ја намалува потрошувачката на ресурси при сложени аналитички пребарувања. |
| | 398 | |