Changes between Version 27 and Version 28 of QueryOptimization


Ignore:
Timestamp:
09/16/26 06:58:05 (13 days ago)
Author:
235013
Comment:

Фаза 3: документација

Legend:

Unmodified
Added
Removed
Modified
  • QueryOptimization

    v27 v28  
    1 = Индекси и оптимизација на прашалници =
    2 
    3 ----
    4 
    5 **Членови на тим**:
    6 
    7 * Никола Маркоски (235013)
    8 * Шенол Фејзоски (231075)
    9 
    10 == View1: Договори по продавач (vw_contracts_per_vendor) ==
    11 
    12 '''1.''' Примарен филтер за погледот `vw_contracts_per_vendor` ќе биде според неговото id (vendor_id на продавачот).
    13 
    14 '''2.''' Примарен случај на употреба ќе е преглед на сите активни и историски договори за одреден продавач. За овој поглед ни се важни перформансите, бидејќи без него се губи време при извршување.
    15 
    16 '''3.''' Иницијалното време за извршување на погледот е '''5s 887ms'''. Ова не е прифатливо време за апликацијата па затоа пристапуваме кон индексирање.
    17 
    18 [[Image(Contracts_per_Vendor_Execution.png, 800px)]]
    19 
    20 '''4.''' Најбавната операција е full scan на табелата:
    21  * `Client_Vendor_Contract` - 7k cost
    22 
    23 [[Image(Contracts_per_Vendor_Scan.png, 800px)]]
    24 
    25 Времето изминато во извршување на операциите insert и update пред индексирање изнесува:
    26 
    27 [[Image(Client_Vendor_Contract_Insert_Pre_Index.png, 800px)]]
    28 
    29 [[Image(Client_Vendor_Contract_Update_Pre_Index.png, 800px)]]
    30 
    31 '''5.''' По креирање на индексите:
    32 
    33 {{{
    34 CREATE INDEX idx_project_contract_id ON Project (contract_id);
    35 CREATE INDEX idx_cvc_vendor_id ON Client_Vendor_Contract (vendor_id);
    36 }}}
    37 
    38 
    39 Времето изминато во извршување на query-то со индекси изнесува:
    40 
    41 [[Image(Contracts_per_Vendor_Execution_After_Indexing.png, 800px)]]
    42 
    43 [[Image(Contracts_per_Vendor_Scan_After_Indexing.png, 800px)]]
    44 
    45 '''6.''' Времето изминато во извршување на операциите insert и update по индексирање изнесува:
    46 
    47 [[Image(Client_Vendor_Contract_Insert_After_Indexing.png, 800px)]]
    48 
    49 [[Image(Client_Vendor_Contract_Update_After_Indexing.png, 800px)]]
    50 
    51 ----
    52 == View2: Договори по клиент (vw_contracts_per_client) ==
    53 
    54 '''1.''' Примарен филтер за погледот `vw_contracts_per_client` ќе биде според неговото id (client_id на клиентот).
    55 
    56 '''2.''' Примарен случај на употреба ќе е преглед на сите активни и историски договори за одреден клиент. За овој поглед ни се важни перформансите, бидејќи без него се губи време при извршување.
    57 
    58 '''3.''' Иницијалното време за извршување на погледот е '''399ms'''. Ова не е прифатливо време за апликацијата па затоа пристапуваме кон индексирање.
    59 
    60 [[Image(Contracts_per_Client_Execution.png, 800px)]]
    61 
    62 '''4.''' Најбавната операција е full scan на табелата:
    63  * `Client_Vendor_Contract` - 7k cost
    64 
    65 [[Image(Contracts_per_Client_Scan.png, 800px)]]
    66 
    67 Времето изминато во извршување на операциите insert и update пред индексирање изнесува:
    68 
    69 [[Image(Client_Vendor_Contract_Insert_Pre_Index.png, 800px)]]
    70 
    71 [[Image(Client_Vendor_Contract_Update_Pre_Index.png, 800px)]]
    72 
    73 '''5.''' Иницијално беше разгледано индексирање преку `idx_cvc_client_id`, меѓутоа мерењата покажаа дека тој индекс го влошува времето на извршување (399ms → 4s 421ms) поради ниска селективност — колоната client_id враќа многу редови по вредност, па планерот прибегнува кон scatter reads наместо секвенцијален скен. Поради тоа, индексот беше отстранет.
    74 
    75 Иако индексите `idx_project_contract_id` и `idx_cvc_vendor_id` од View1 се присутни, планот за извршување останува непроменет — табелата `Client_Vendor_Contract` сеуште се скенира секвенцијално со ист cost од 7k, бидејќи овие индекси не се применливи за филтрирање по client_id. Разликата во времето на извршување од ~100ms е во рамките на нормална варијација и не може да се припише на индексирањето. Се заклучува дека овој поглед не може да се оптимизира преку индексирање.
    76 
    77 [[Image(Contracts_per_Client_Execution_After_Indexing.png, 800px)]]
    78 
    79 [[Image(Contracts_per_Client_Scan_After_Indexing.png, 800px)]]
    80 
    81 '''6.''' Времето на извршување на операциите insert и update останува непроменето. Забележаните разлики во мерењата се должат на надворешни фактори како cache состојба и системска активност, а не на индексирањето.
    82 
    83 [[Image(Client_Vendor_Contract_Insert_After_Indexing.png, 800px)]]
    84 
    85 [[Image(Client_Vendor_Contract_Update_After_Indexing.png, 800px)]]
    86 
    87 ----
    88 
    89 == View3: Проекти по продавач (vw_projects_per_vendor) ==
    90 
    91 '''1.''' Примарен филтер за погледот `vw_projects_per_vendor` ќе биде според неговото id (vendor_id на продавачот).
    92 
    93 '''2.''' Примарен случај на употреба ќе е преглед на сите проекти поврзани со одреден продавач. За овој поглед ни се важни перформансите, бидејќи без него се губи време при извршување.
    94 
    95 '''3.''' Иницијалното време за извршување на погледот е '''445ms'''. Ова не е прифатливо време за апликацијата па затоа пристапуваме кон индексирање.
    96 
    97 [[Image(Projects_per_Vendor_Execution.png, 800px)]]
    98 
    99 '''4.''' Најбавните операции се full scan на табелите:
    100  * `Project` - 26k cost
    101  * `Client_Vendor_Contract` - 7k cost
    102 
    103 [[Image(Projects_per_Vendor_Scan.png, 800px)]]
    104 
    105 Времето изминато во извршување на операциите insert и update пред индексирање изнесува:
    106 
    107 [[Image(Project_Insert_Pre_Index.png, 800px)]]
    108 
    109 [[Image(Project_Update_Pre_Index.png, 800px)]]
    110 
    111 [[Image(Client_Vendor_Contract_Insert_Pre_Index.png, 800px)]]
    112 
    113 [[Image(Client_Vendor_Contract_Update_Pre_Index.png, 800px)]]
    114 
    115 '''5.''' Иако овој поглед не е аналитички и би имал потреба од индексирање, индексите `idx_project_contract_id` и `idx_cvc_vendor_id` креирани во View1 ги покриваат потребните колони за овој поглед. Времето изминато во извршување на query-то изнесува:
    116 
    117 [[Image(Projects_per_Vendor_Execution_After_Indexing.png, 800px)]]
    118 
    119 [[Image(Projects_per_Vendor_Scan_After_Indexing.png, 800px)]]
    120 
    121 '''6.''' Времето изминато во извршување на операциите insert и update по индексирање изнесува:
    122 
    123 [[Image(Project_Insert_After_Indexing.png, 800px)]]
    124 
    125 [[Image(Project_Update_After_Indexing.png, 800px)]]
    126 
    127 [[Image(Client_Vendor_Contract_Insert_After_Indexing.png, 800px)]]
    128 
    129 [[Image(Client_Vendor_Contract_Update_After_Indexing.png, 800px)]]
    130 
    131 ----
    132 
    133 == View4: Проекти по клиент (vw_projects_per_client) ==
    134 
    135 '''1.''' Примарен филтер за погледот `vw_projects_per_client` ќе биде според неговото id (client_id на клиентот).
    136 
    137 '''2.''' Примарен случај на употреба ќе е преглед на сите проекти поврзани со одреден клиент. За овој поглед ни се важни перформансите, бидејќи без него се губи време при извршување.
    138 
    139 '''3.''' Иницијалното време за извршување на погледот е '''626ms'''. Ова не е прифатливо време за апликацијата па затоа пристапуваме кон индексирање.
    140 
    141 [[Image(Projects_per_Client_Execution.png, 800px)]]
    142 
    143 '''4.''' Најбавните операции се full scan на табелите:
    144  * `Project` - 26k cost
    145  * `Client_Vendor_Contract` - 7k cost
    146 
    147 [[Image(Projects_per_Client_Scan.png, 800px)]]
    148 
    149 Времето изминато во извршување на операциите insert и update пред индексирање изнесува:
    150 
    151 [[Image(Project_Insert_Pre_Index.png, 800px)]]
    152 
    153 [[Image(Project_Update_Pre_Index.png, 800px)]]
    154 
    155 [[Image(Client_Vendor_Contract_Insert_Pre_Index.png, 800px)]]
    156 
    157 [[Image(Client_Vendor_Contract_Update_Pre_Index.png, 800px)]]
    158 
    159 '''5.''' Иницијално беше разгледано индексирање преку `idx_cvc_client_id`, меѓутоа мерењата покажаа дека тој индекс го влошува времето на извршување (626ms → 2s 636ms) поради ниска селективност на client_id колоната. По отстранување на тој индекс, перформансите на овој поглед се подобрени преку индексите `idx_project_contract_id` и `idx_cvc_vendor_id` креирани во View1. Времето изминато во извршување на query-то изнесува:
    160 
    161 [[Image(Projects_per_Client_Execution_After_Indexing.png, 800px)]]
    162 
    163 [[Image(Projects_per_Client_Scan_After_Indexing.png, 800px)]]
    164 
    165 '''6.''' Времето изминато во извршување на операциите insert и update по индексирање изнесува:
    166 
    167 [[Image(Project_Insert_After_Indexing.png, 800px)]]
    168 
    169 [[Image(Project_Update_After_Indexing.png, 800px)]]
    170 
    171 [[Image(Client_Vendor_Contract_Insert_After_Indexing.png, 800px)]]
    172 
    173 [[Image(Client_Vendor_Contract_Update_After_Indexing.png, 800px)]]
    174 
    175 ----
    176 
    177 == View5: Клиенти по индустрија (vw_clients_per_industry) ==
    178 
    179 '''1.''' Примарен филтер за погледот `vw_clients_per_industry` ќе биде според неговото id (industry_id на индустријата).
    180 
    181 '''2.''' Примарен случај на употреба ќе е преглед на сите клиенти кои припаѓаат на одредена индустрија. За овој поглед ни се важни перформансите, бидејќи без него се губи време при извршување.
    182 
    183 '''3.''' Иницијалното време за извршување на погледот е '''94ms'''. Иако на прв поглед ова изгледа прифатливо, беше разгледано дали индексирање би го подобрило времето.
    184 
    185 [[Image(Clients_per_Industry_Execution.png, 800px)]]
    186 
    187 Времето изминато во извршување на операциите insert и update изнесува:
    188 
    189 [[Image(Client_Insert_Pre_Index.png, 800px)]]
    190 
    191 [[Image(Client_Update_Pre_Index.png, 800px)]]
    192 
    193 '''4.''' По тестирање на индексот `idx_client_industry_id ON Client (industry_id)`, мерењата покажаа дека индексот го влошува времето на извршување (94ms → 1s 166ms). Табелата `Client` е доволно мала (500 cost) за планерот да претпочита секвенцијален скен. Поради тоа, индексот беше отстранет и се заклучува дека нема потреба од индексирање за овој поглед.
    194 
    195 '''5.''' Нема потреба да се преуреди прашалникот.
    196 
    197 '''6.''' Времето на извршување на операциите останува исто.
    198 
    199 ----
    200 
    201 == View6: Нерешени тикети за спорови (vw_unresolved_dispute_tickets) ==
    202 
    203 '''1.''' Примарен филтер за погледот `vw_unresolved_dispute_tickets` ќе биде според project_id на проектот или assigned_management_user_id на корисникот.
    204 
    205 '''2.''' Примарен случај на употреба ќе е преглед на сите активни нерешени тикети за спорови доделени на одреден менаџмент корисник или поврзани со одреден проект. За овој поглед ни се важни перформансите, бидејќи без него се губи време при извршување.
    206 
    207 '''3.''' Иницијалното време за извршување на погледот е '''731ms'''. Ова не е прифатливо време за апликацијата па затоа пристапуваме кон индексирање.
    208 
    209 [[Image(Unresolved_Dispute_Tickets_Execution.png, 800px)]]
    210 
    211 '''4.''' Најбавната операција е full scan на табелата:
    212  * `Dispute_Ticket` - 9k cost
    213 
    214 [[Image(Unresolved_Dispute_Tickets_Scan.png, 800px)]]
    215 
    216 Времето изминато во извршување на операциите insert и update пред индексирање изнесува:
    217 
    218 [[Image(Dispute_Ticket_Insert_Pre_Index.png, 800px)]]
    219 
    220 [[Image(Dispute_Ticket_Update_Pre_Index.png, 800px)]]
    221 
    222 '''5.''' По креирање на индексите:
    223 
    224 {{{
    225 CREATE INDEX idx_dispute_ticket_review_id ON Dispute_Ticket (review_id);
    226 CREATE INDEX idx_dispute_ticket_is_resolved ON Dispute_Ticket (is_resolved);
    227 }}}
    228 
    229 Времето изминато во извршување на query-то со индекси изнесува (731ms → 194ms):
    230 
    231 [[Image(Unresolved_Dispute_Tickets_Execution_After_Indexing.png, 800px)]]
    232 
    233 [[Image(Unresolved_Dispute_Tickets_Scan_After_Indexing.png, 800px)]]
    234 
    235 '''6.''' Времето изминато во извршување на операциите insert и update по индексирање изнесува:
    236 
    237 [[Image(Dispute_Ticket_Insert_After_Indexing.png, 800px)]]
    238 
    239 [[Image(Dispute_Ticket_Update_After_Indexing.png, 800px)]]
    240 
    241 ----
    242 
    243 == View7: Претплати на продавачи (vw_vendor_subscriptions) ==
    244 
    245 '''1.''' Примарен филтер за погледот `vw_vendor_subscriptions` ќе биде според неговото id (vendor_id на продавачот).
    246 
    247 '''2.''' Примарен случај на употреба ќе е преглед на активните и историските претплати за одреден продавач. За овој поглед ни се важни перформансите, бидејќи без него се губи време при извршување.
    248 
    249 '''3.''' Иницијалното време за извршување на погледот е '''37ms'''. Ова е прифатливо време за апликацијата, па затоа нема потреба од индексирање.
    250 
    251 [[Image(Vendor_Subscriptions_Execution.png, 800px)]]
    252 
    253 Времето изминато во извршување на операциите insert и update изнесува:
    254 
    255 [[Image(Vendor_Subscription_Insert_Pre_Index.png, 800px)]]
    256 
    257 [[Image(Vendor_Subscription_Update_Pre_Index.png, 800px)]]
    258 
    259 '''4.''' Нема потреба да се преуреди прашалникот.
    260 
    261 '''5.''' Времето на извршување на операциите останува исто.
    262 
    263 ----
    264 
    265 == View8: Просечна оценка по продавач (vw_avg_rating_per_vendor) ==
    266 
    267 '''1.''' Примарен филтер за погледот `vw_avg_rating_per_vendor` ќе биде според неговото id (vendor_id на продавачот).
    268 
    269 '''2.''' Примарен случај на употреба ќе е преглед на просечната оценка на секој продавач врз основа на рецензии од проекти. Овој поглед е аналитички по природа (пресметува агрегатни вредности со AVG и COUNT) и не бара директно индексирање. Сепак, перформансите на овој поглед се подобрени поради индексирањето применето во View1.
    270 
    271 '''3.''' Иницијалното време за извршување на погледот е '''1m 24s 217ms'''.
    272 
    273 [[Image(Average_Rating_Execution.png, 800px)]]
    274 
    275 
    276 '''4.''' Иако овој поглед е аналитички и не бара директно индексирање, перформансите се подобрени поради индексите `idx_project_contract_id` и `idx_cvc_vendor_id` креирани во View1. Времето изминато во извршување на query-то по индексирање изнесува:
    277 
    278 [[Image(Average_Rating_per_Vendor_Execution_After_Indexing.png, 800px)]]
    279 
    280 
    281 '''5.''' Времето на извршување на операциите insert и update останува непроменето бидејќи не се додадени нови индекси во овој поглед.
    282 
    283 ----
    284 
    285 == View9: Вкупен буџет по клиент (vw_budget_per_client) ==
    286 
    287 '''1.''' Примарен филтер за погледот `vw_budget_per_client` ќе биде според неговото id (client_id на клиентот).
    288 
    289 '''2.''' Примарен случај на употреба ќе е преглед на вкупниот буџет потрошен по клиент низ сите проекти и договори. Овој поглед е аналитички по природа (пресметува агрегатни вредности со SUM и COUNT) и не бара директно индексирање.
    290 
    291 '''3.''' Иницијалното време за извршување на погледот е '''320ms'''.
    292 
    293 
    294 [[Image(Budget_per_Client_Execution.png, 800px)]]
    295 
    296 '''4.''' Иако овој поглед е аналитички и не бара директно индексирање, перформансите се подобрени поради индексите `idx_project_contract_id` и `idx_cvc_vendor_id` креирани во View1. Времето изминато во извршување на query-то по индексирање изнесува:
    297 
    298 [[Image(Budget_per_Client_Execution_After_Indexing.png, 800px)]]
    299 
    300 
    301 '''6.''' Времето на извршување на операциите insert и update останува непроменето бидејќи не се додадени нови индекси за овој поглед.
    302 
    303 ----
    304 
    305 == View10: Вкупен буџет по продавач (vw_budget_per_vendor) ==
    306 
    307 '''1.''' Примарен филтер за погледот `vw_budget_per_vendor` ќе биде според неговото id (vendor_id на продавачот).
    308 
    309 '''2.''' Примарен случај на употреба ќе е преглед на вкупниот буџет потрошен по продавач низ сите проекти и договори. Овој поглед е аналитички по природа (пресметува агрегатни вредности со SUM и COUNT) и не бара директно индексирање. Сепак, перформансите на овој поглед се подобрени поради индексирањето применето во View1.
    310 
    311 '''3.''' Иницијалното време за извршување на погледот е '''319ms'''.
    312 
    313 [[Image(Budget_per_Vendor_Execution.png, 800px)]]
    314 
    315 '''4.''' Иако овој поглед е аналитички и не бара директно индексирање, перформансите се подобрени поради индексите `idx_project_contract_id` и `idx_cvc_vendor_id` креирани во View1. Времето изминато во извршување на query-то по индексирање изнесува:
    316 
    317 [[Image(Budget_per_Vendor_Execution_After_Indexing.png, 800px)]]
    318 
    319 '''5.''' Времето на извршување на операциите insert и update останува непроменето бидејќи не се додадени нови индекси за овој поглед.
    320 
    321 ----
    322 
    323 == View11: Број на проекти по статус по клиент (vw_project_count_by_status_per_client) ==
    324 
    325 '''1.''' Примарен филтер за погледот `vw_project_count_by_status_per_client` ќе биде според неговото id (client_id на клиентот).
    326 
    327 '''2.''' Примарен случај на употреба ќе е преглед на бројот на проекти групирани по статус за одреден клиент. Овој поглед е аналитички по природа (пресметува агрегатни вредности со COUNT и GROUP BY) и не бара директно индексирање.
    328 
    329 '''3.''' Иницијалното времe за извршување на погледот е '''317ms'''.
    330 
    331 [[Image(Project_Count_By_Status_Per_Client_Execution.png, 800px)]]
    332 
    333 
    334 '''4.''' Иако овој поглед е аналитички и не бара директно индексирање, перформансите се подобрени поради индексите `idx_project_contract_id` и `idx_cvc_vendor_id` креирани во View1. Времето изминато во извршување на query-то по индексирање изнесува:
    335 
    336 [[Image(Project_Count_by_Status_per_Client_Execution_After_Indexing.png, 800px)]]
    337 
    338 
    339 '''5.''' Времето на извршување на операциите insert и update останува непроменето бидејќи не се додадени нови индекси за овој поглед.
    340 
    341 ----
    342 
    343 == View12: Број на проекти по статус по продавач (vw_project_count_by_status_per_vendor) ==
    344 
    345 '''1.''' Примарен филтер за погледот `vw_project_count_by_status_per_vendor` ќе биде според неговото id (vendor_id на продавачот).
    346 
    347 '''2.''' Примарен случај на употреба ќе е преглед на бројот на проекти групирани по статус за одреден продавач. Овој поглед е аналитички по природа (пресметува агрегатни вредности со COUNT и GROUP BY) и не бара директно индексирање. Сепак, перформансите на овој поглед се променети поради индексирањето применето во View1.
    348 
    349 '''3.''' Иницијалното време за извршување на погледот е '''317ms'''.
    350 
    351 [[Image(Project_Count_By_Status_Per_Vendor_Execution.png, 800px)]]
    352 
    353 
    354 '''4.''' Иако овој поглед е аналитички и не бара директно индексирање, перформансите се променети поради индексите `idx_project_contract_id` и `idx_cvc_vendor_id` креирани во View1. Времето изминато во извршување на query-то по индексирање изнесува:
    355 
    356 [[Image(Project_Count_by_Status_per_Vendor_Execution_After_Indexing.png, 800px)]]
    357 
    358 '''5.''' Тука може да се забележи дека перформансите се 'полоши' после индексирање, но бидејќи погледот е аналитички, и истите индекси ги подобрија повеќето од другите погледи, не правиме промени.
    359 
    360 '''6.''' Времето на извршување на операциите insert и update останува непроменето бидејќи не се додадени нови индекси за овој поглед.
     1= Индекси и оптимизација на прашалници (!QueryOptimization) =
     2
     3Во оваа фаза се анализирани перформансите на погледите од фаза 2Б, по потреба се преуредени прашалниците и се додадени индекси. Погледите се нумерирани како на DatabaseCreation; опфатени се погледите 3–14 (1 и 2 се помошни, а 15 и 16 се додадени по оваа фаза).
     4
     5Мерењата се направени врз целото податочно множество со `EXPLAIN (ANALYZE, BUFFERS)`; секој прашалник е извршен три пати, а наведено е просечното време од второто и третото извршување, кога податоците се веќе во баферите. „Без индексите“ е базата само со индексите од шемата (примарни клучеви и уникатни ограничувања), „со индексите“ е базата и со двата индекса од оваа фаза. Без филтер планот е ист во двата случаја и разликите во времето се варијација меѓу извршувањата.
     6
     7Репрезентативни вредности за филтрите:
     8
     9* `vendor_id = 4242`: 47 договори, 276 проекти
     10* `client_id = 4242`: 7 договори, 52 проекти
     11* `industry_id = 7`: 968 клиенти
     12* `project_id = 142160`
     13
     14[[PageOutline(2-3,Содржина,inline)]]
     15
     16== Индекси ==
     17
     18[attachment:indexes.sql]
     19
     20{{{#!sql
     21CREATE INDEX IF NOT EXISTS idx_cvc_vendor_id ON Client_Vendor_Contract (vendor_id);
     22CREATE INDEX IF NOT EXISTS idx_cvc_client_id ON Client_Vendor_Contract (client_id);
     23}}}
     24
     25||= Индекс =||= Големина =||= Намена =||
     26|| `idx_cvc_vendor_id` || 1,7 MB || погледите филтрирани по софтверска агенција (3, 5, 8, 10, 12) ||
     27|| `idx_cvc_client_id` || 2,1 MB || погледите филтрирани по клиент (4, 6, 11, 13) ||
     28
     29Секој поглед филтриран по агенција или по клиент почнува со договорите на таа агенција или на тој клиент. Без индекс тоа е sequential scan на целата табела `Client_Vendor_Contract` (250.000 редици, 5.652 страници) за да се задржат 47, односно 12 редици; со индексот се читаат само тие редици. Одлуката е според планот, а не според милисекундите: план што чита цела табела за неколку десетици редици е погрешен независно од големината на табелата, а индексот чини 2 MB. Останатите чекори на тие погледи (проектите на договорот, статусот, двете страни) веќе одат преку индексите од шемата: примарните клучеви и `uq_project_contract_name`, чија прва колона е `contract_id`.
     30
     31=== Индекси што не се задржани === #not-kept
     32
     33Секој кандидат е креиран во трансакција што се поништува и измерен на истиот начин.
     34
     35||= Индекс =||= Големина =||= Мерење =||= Причина =||
     36|| `idx_project_contract_id ON Project (contract_id)` || 15 MB || поглед 3 филтриран: 0,85 ms без, 0,82 ms со || поврзувањето договор → проекти веќе оди преку `uq_project_contract_name`; планот е ист, само индексот е потесен ||
     37|| `idx_dispute_ticket_review_id ON Dispute_Ticket (review_id)` || 3,1 MB || сите спорови на една рецензија: 9,17 ms без, 0,01 ms со || отворените спорови на рецензија (проверката при објавување и при поднесување спор) веќе ги покрива `uq_dispute_open_per_vendor_review`; читањето на сите спорови на една рецензија е ретко и 9,17 ms е прифатливо ||
     38|| `idx_pba_project_id ON Project_Budget_Audit (project_id)` || 20 MB || промените на буџет на еден проект (поглед 16): 29,5 ms без, 0,06 ms со || табелата се запишува при секоја промена на буџет, а се чита ретко; 29,5 ms е прифатливо за ревизиски преглед ||
     39|| `idx_client_industry_id ON Client (industry_id)` || 160 kB || поглед 7 филтриран: 2,65 ms без, 1,75 ms со || 968-те клиенти на една индустрија (5 % од табелата) се распоредени низ речиси сите страници, па и со индексот се читаат речиси сите ||
     40|| `idx_dispute_ticket_is_resolved ON Dispute_Ticket (is_resolved)` || 992 kB || поглед 9: ист план || условот `is_resolved = false` избира 40 % од табелата, па оптимизаторот не го користи индексот ||
     41
     42=== Цена при запишување === #write-cost
     43
     44По 10.000 редици `INSERT` и `UPDATE` во `Client_Vendor_Contract`, единствената табела со индекс од оваа фаза, во трансакција што се поништува; `UPDATE` менува неиндексирана колона (наслов на договор).
     45
     46||= Наредба (10.000 редици) =||= Без индексите =||= Со индексите =||
     47|| `INSERT` во `Client_Vendor_Contract` || 225 ms || 240 ms ||
     48|| `UPDATE` на `Client_Vendor_Contract` || 285 ms || 321 ms ||
     49
     50Индексите го поскапуваат запишувањето за 7 до 13 %; најголемиот дел од времето отпаѓа на проверките на надворешните клучеви и тригерите.
     51
     52----
     53
     54== Поглед 3: Проекти по софтверска агенција (vw_projects_per_vendor) ==
     55
     56'''1.''' Примарен филтер за погледот `vw_projects_per_vendor` ќе биде според `vendor_id` на софтверската агенција.
     57
     58'''2.''' Примарен случај на употреба ќе биде преглед на сите проекти на одредена софтверска агенција, на нејзината контролна табла и на профилот што клиентот го разгледува. Перформансите на овој поглед се важни, бидејќи се чита при секое отворање на профилот.
     59
     60'''3.''' Иницијална состојба: најбавната операција е sequential scan на табелата `Client_Vendor_Contract` (250.000 редици, 5.652 страници), паралелен, со отфрлање на 249.953 редици; проектите на секој договор се читаат преку уникатниот индекс `uq_project_contract_name (contract_id, project_name)` од шемата.
     61
     62{{{
     63Sort  (actual time=11.781..14.928 rows=276 loops=1)
     64  Sort Key: v.agency_name, ps.status_name, p.project_name
     65  ->  Nested Loop  (actual time=0.912..14.484 rows=276 loops=1)
     66        ->  Index Scan using vendor_pkey on vendor v  (actual time=0.010..0.011 rows=1 loops=1)
     67              Index Cond: (vendor_id = 4242)
     68        ->  Gather  (actual time=0.900..14.436 rows=276 loops=1)
     69              Workers Launched: 2
     70              ->  Hash Join  (actual time=0.451..8.896 rows=92 loops=3)
     71                    Hash Cond: (p.status_id = ps.status_id)
     72                    ->  Nested Loop  (actual time=0.364..8.790 rows=92 loops=3)
     73                          ->  Nested Loop  (actual time=0.338..8.549 rows=16 loops=3)
     74                                ->  Parallel Seq Scan on client_vendor_contract cvc  (actual time=0.321..8.451 rows=16 loops=3)
     75                                      Filter: (vendor_id = 4242)
     76                                      Rows Removed by Filter: 83318
     77                                ->  Index Only Scan using client_pkey on client c  (actual time=0.005..0.005 rows=1 loops=47)
     78                                      Index Cond: (client_id = cvc.client_id)
     79                          ->  Index Scan using uq_project_contract_name on project p  (actual time=0.013..0.014 rows=6 loops=47)
     80                                Index Cond: (contract_id = cvc.contract_id)
     81                    ->  Hash  (actual time=0.019..0.019 rows=6 loops=3)
     82                          [...]
     83Execution Time: 14.978 ms
     84}}}
     85
     86'''4.''' Индексирање: `idx_cvc_vendor_id` за договорите на агенцијата. Проектите на секој договор и понатаму се читаат преку `uq_project_contract_name`, уникатниот индекс од шемата чија прва колона е `contract_id`.
     87
     88{{{
     89Sort  (actual time=0.851..0.862 rows=276 loops=1)
     90  Sort Key: v.agency_name, ps.status_name, p.project_name
     91  ->  Nested Loop  (actual time=0.042..0.421 rows=276 loops=1)
     92        ->  Nested Loop  (actual time=0.038..0.333 rows=276 loops=1)
     93              ->  Nested Loop  (actual time=0.031..0.139 rows=47 loops=1)
     94                    ->  Index Scan using vendor_pkey on vendor v  (actual time=0.008..0.009 rows=1 loops=1)
     95                          Index Cond: (vendor_id = 4242)
     96                    ->  Nested Loop  (actual time=0.022..0.125 rows=47 loops=1)
     97                          ->  Bitmap Heap Scan on client_vendor_contract cvc  (actual time=0.016..0.051 rows=47 loops=1)
     98                                Recheck Cond: (vendor_id = 4242)
     99                                ->  Bitmap Index Scan on idx_cvc_vendor_id  (actual time=0.008..0.008 rows=47 loops=1)
     100                                      Index Cond: (vendor_id = 4242)
     101                          ->  Index Only Scan using client_pkey on client c  (actual time=0.001..0.001 rows=1 loops=47)
     102                                Index Cond: (client_id = cvc.client_id)
     103              ->  Index Scan using uq_project_contract_name on project p  (actual time=0.003..0.003 rows=6 loops=47)
     104                    Index Cond: (contract_id = cvc.contract_id)
     105        ->  Memoize  (actual time=0.000..0.000 rows=1 loops=276)
     106              [...]
     107Execution Time: 0.892 ms
     108}}}
     109
     110'''5.''' Време на извршување:
     111
     112||= Читање =||= Без индексите =||= Со индексите =||= Забрзување =||
     113|| филтрирано по софтверска агенција (276 редици) || 15,7 ms || 0,85 ms || 18 пати ||
     114|| нефилтрирано (1.400.000 редици) || 2,28 s || 2,40 s || ист план ||
     115
     116'''6.''' Времето на извршување на операциите insert и update врз табелите на погледот е во табелата [#write-cost „Цена при запишување“] на почетокот на страницата.
     117
     118----
     119
     120== Поглед 4: Проекти по клиент (vw_projects_per_client) ==
     121
     122'''1.''' Примарен филтер за погледот `vw_projects_per_client` ќе биде според `client_id` на клиентот.
     123
     124'''2.''' Примарен случај на употреба ќе биде преглед на сите проекти на одреден клиент, на неговата контролна табла.
     125
     126'''3.''' Иницијална состојба: најбавната операција е sequential scan на табелата `Client_Vendor_Contract` со филтер по `client_id`, со отфрлање на 249.993 редици; проектите се читаат преку `uq_project_contract_name`.
     127
     128{{{
     129Gather Merge  (actual time=11.490..14.589 rows=52 loops=1)
     130  Workers Launched: 2
     131  ->  Sort  (actual time=8.920..8.923 rows=17 loops=3)
     132        Sort Key: c.company_name, ps.status_name, p.project_name
     133        ->  Hash Join  (actual time=2.665..8.868 rows=17 loops=3)
     134              Hash Cond: (p.status_id = ps.status_id)
     135              ->  Nested Loop  (actual time=2.587..8.785 rows=17 loops=3)
     136                    ->  Nested Loop  (actual time=2.543..8.713 rows=2 loops=3)
     137                          ->  Nested Loop  (actual time=2.526..8.689 rows=2 loops=3)
     138                                ->  Parallel Seq Scan on client_vendor_contract cvc  (actual time=2.506..8.661 rows=2 loops=3)
     139                                      Filter: (client_id = 4242)
     140                                      Rows Removed by Filter: 83331
     141                                ->  Index Scan using client_pkey on client c  (actual time=0.010..0.010 rows=1 loops=7)
     142                                      Index Cond: (client_id = 4242)
     143                          ->  Index Only Scan using vendor_pkey on vendor v  (actual time=0.009..0.009 rows=1 loops=7)
     144                                Index Cond: (vendor_id = cvc.vendor_id)
     145                    ->  Index Scan using uq_project_contract_name on project p  (actual time=0.026..0.028 rows=7 loops=7)
     146                          Index Cond: (contract_id = cvc.contract_id)
     147              ->  Hash  (actual time=0.014..0.014 rows=6 loops=3)
     148                    [...]
     149Execution Time: 14.625 ms
     150}}}
     151
     152'''4.''' Индексирање: `idx_cvc_client_id` за договорите на клиентот; проектите се читаат преку `uq_project_contract_name`. Колоната `client_id` има 20.000 различни вредности, просечно 12,5 договори по клиент, па е поселективна од `vendor_id` (5.000 вредности, 50 договори по агенција).
     153
     154{{{
     155Sort  (actual time=0.154..0.157 rows=52 loops=1)
     156  Sort Key: c.company_name, ps.status_name, p.project_name
     157  ->  Nested Loop  (actual time=0.038..0.096 rows=52 loops=1)
     158        ->  Nested Loop  (actual time=0.032..0.070 rows=52 loops=1)
     159              ->  Nested Loop  (actual time=0.024..0.038 rows=7 loops=1)
     160                    ->  Nested Loop  (actual time=0.017..0.023 rows=7 loops=1)
     161                          ->  Index Scan using client_pkey on client c  (actual time=0.006..0.007 rows=1 loops=1)
     162                                Index Cond: (client_id = 4242)
     163                          ->  Bitmap Heap Scan on client_vendor_contract cvc  (actual time=0.009..0.013 rows=7 loops=1)
     164                                Recheck Cond: (client_id = 4242)
     165                                ->  Bitmap Index Scan on idx_cvc_client_id  (actual time=0.005..0.005 rows=7 loops=1)
     166                                      Index Cond: (client_id = 4242)
     167                    ->  Index Only Scan using vendor_pkey on vendor v  (actual time=0.002..0.002 rows=1 loops=7)
     168                          Index Cond: (vendor_id = cvc.vendor_id)
     169              ->  Index Scan using uq_project_contract_name on project p  (actual time=0.003..0.004 rows=7 loops=7)
     170                    Index Cond: (contract_id = cvc.contract_id)
     171        ->  Memoize  (actual time=0.000..0.000 rows=1 loops=52)
     172              [...]
     173Execution Time: 0.182 ms
     174}}}
     175
     176'''5.''' Време на извршување:
     177
     178||= Читање =||= Без индексите =||= Со индексите =||= Забрзување =||
     179|| филтрирано по клиент (52 редици) || 14,5 ms || 0,17 ms || 86 пати ||
     180|| нефилтрирано (1.400.000 редици) || 2,15 s || 2,23 s || ист план ||
     181
     182'''6.''' Времето на извршување на операциите insert и update врз табелите на погледот е во табелата [#write-cost „Цена при запишување“] на почетокот на страницата.
     183
     184----
     185
     186== Поглед 5: Вкупен буџет по софтверска агенција (vw_budget_per_vendor) ==
     187
     188'''1.''' Примарен филтер за погледот `vw_budget_per_vendor` ќе биде според `vendor_id` на софтверската агенција.
     189
     190'''2.''' Примарен случај на употреба ќе биде преглед на вкупниот буџет на проектите на агенцијата, по валута. Погледот е аналитички (`SUM`, `COUNT`, `GROUP BY`).
     191
     192'''3.''' Иницијална состојба: филтрирано, најбавната операција е sequential scan на `Client_Vendor_Contract`; нефилтрирано, планот е паралелен hash join на sequential scan на `Project` и `Client_Vendor_Contract` со агрегација (`HashAggregate`), кај кој индексите не помагаат.
     193
     194{{{
     195Sort  (actual time=11.086..14.206 rows=6 loops=1)
     196  Sort Key: v.agency_name, cvc.currency_code
     197  ->  GroupAggregate  (actual time=10.951..14.198 rows=6 loops=1)
     198        Group Key: cvc.currency_code
     199        ->  Nested Loop  (actual time=10.935..14.157 rows=276 loops=1)
     200              ->  Gather Merge  (actual time=10.911..14.071 rows=276 loops=1)
     201                    Workers Launched: 2
     202                    ->  Sort  (actual time=8.099..8.104 rows=92 loops=3)
     203                          Sort Key: cvc.currency_code
     204                          ->  Hash Join  (actual time=0.938..8.045 rows=92 loops=3)
     205                                Hash Cond: (p.status_id = ps.status_id)
     206                                ->  Nested Loop  (actual time=0.837..7.923 rows=92 loops=3)
     207                                      ->  Nested Loop  (actual time=0.810..7.718 rows=16 loops=3)
     208                                            ->  Parallel Seq Scan on client_vendor_contract cvc  (actual time=0.790..7.622 rows=16 loops=3)
     209                                                  Filter: (vendor_id = 4242)
     210                                                  Rows Removed by Filter: 83318
     211                                            ->  Index Only Scan using client_pkey on client c  (actual time=0.005..0.005 rows=1 loops=47)
     212                                                  Index Cond: (client_id = cvc.client_id)
     213                                      ->  Index Scan using uq_project_contract_name on project p  (actual time=0.011..0.012 rows=6 loops=47)
     214                                            Index Cond: (contract_id = cvc.contract_id)
     215                                ->  Hash  (actual time=0.018..0.018 rows=6 loops=3)
     216                                      [...]
     217              ->  Materialize  (actual time=0.000..0.000 rows=1 loops=276)
     218                    [...]
     219Execution Time: 14.262 ms
     220}}}
     221
     222'''4.''' Индексирање: `idx_cvc_vendor_id`; агрегацијата по валута потоа работи врз 276 редици.
     223
     224{{{
     225Sort  (actual time=0.548..0.549 rows=6 loops=1)
     226  Sort Key: v.agency_name, cvc.currency_code
     227  ->  GroupAggregate  (actual time=0.486..0.545 rows=6 loops=1)
     228        Group Key: cvc.currency_code
     229        ->  Sort  (actual time=0.480..0.490 rows=276 loops=1)
     230              Sort Key: cvc.currency_code
     231              ->  Nested Loop  (actual time=0.032..0.407 rows=276 loops=1)
     232                    ->  Nested Loop  (actual time=0.026..0.321 rows=276 loops=1)
     233                          ->  Nested Loop  (actual time=0.021..0.129 rows=47 loops=1)
     234                                ->  Index Scan using vendor_pkey on vendor v  (actual time=0.005..0.006 rows=1 loops=1)
     235                                      Index Cond: (vendor_id = 4242)
     236                                ->  Nested Loop  (actual time=0.015..0.118 rows=47 loops=1)
     237                                      ->  Bitmap Heap Scan on client_vendor_contract cvc  (actual time=0.010..0.047 rows=47 loops=1)
     238                                            Recheck Cond: (vendor_id = 4242)
     239                                            ->  Bitmap Index Scan on idx_cvc_vendor_id  (actual time=0.004..0.004 rows=47 loops=1)
     240                                                  Index Cond: (vendor_id = 4242)
     241                                      ->  Index Only Scan using client_pkey on client c  (actual time=0.001..0.001 rows=1 loops=47)
     242                                            Index Cond: (client_id = cvc.client_id)
     243                          ->  Index Scan using uq_project_contract_name on project p  (actual time=0.003..0.003 rows=6 loops=47)
     244                                Index Cond: (contract_id = cvc.contract_id)
     245                    ->  Memoize  (actual time=0.000..0.000 rows=1 loops=276)
     246                          [...]
     247Execution Time: 0.574 ms
     248}}}
     249
     250'''5.''' Време на извршување:
     251
     252||= Читање =||= Без индексите =||= Со индексите =||= Забрзување =||
     253|| филтрирано по софтверска агенција (6 редици) || 14,3 ms || 0,52 ms || 27 пати ||
     254|| нефилтрирано (28.738 редици) || 605 ms || 608 ms || ист план ||
     255
     256'''6.''' Времето на извршување на операциите insert и update врз табелите на погледот е во табелата [#write-cost „Цена при запишување“] на почетокот на страницата.
     257
     258----
     259
     260== Поглед 6: Вкупен буџет по клиент (vw_budget_per_client) ==
     261
     262'''1.''' Примарен филтер за погледот `vw_budget_per_client` ќе биде според `client_id` на клиентот.
     263
     264'''2.''' Примарен случај на употреба ќе биде преглед на вкупниот буџет на клиентот низ сите проекти и договори, по валута. Погледот е аналитички (`SUM`, `COUNT`, `GROUP BY`).
     265
     266'''3.''' Иницијална состојба: филтрирано, најбавната операција е sequential scan на `Client_Vendor_Contract`; нефилтрирано, планот е hash join на sequential scan на `Project` и `Client_Vendor_Contract` со агрегација (`HashAggregate`), кај кој индексите не помагаат.
     267
     268{{{
     269Sort  (actual time=12.035..15.191 rows=3 loops=1)
     270  Sort Key: c.company_name, cvc.currency_code
     271  ->  GroupAggregate  (actual time=11.979..15.182 rows=3 loops=1)
     272        Group Key: cvc.currency_code
     273        ->  Nested Loop  (actual time=11.960..15.155 rows=52 loops=1)
     274              ->  Gather Merge  (actual time=11.929..15.097 rows=52 loops=1)
     275                    Workers Launched: 2
     276                    ->  Sort  (actual time=9.209..9.212 rows=17 loops=3)
     277                          Sort Key: cvc.currency_code
     278                          ->  Hash Join  (actual time=2.709..9.165 rows=17 loops=3)
     279                                Hash Cond: (p.status_id = ps.status_id)
     280                                ->  Nested Loop  (actual time=2.616..9.067 rows=17 loops=3)
     281                                      ->  Nested Loop  (actual time=2.591..9.009 rows=2 loops=3)
     282                                            ->  Parallel Seq Scan on client_vendor_contract cvc  (actual time=2.569..8.978 rows=2 loops=3)
     283                                                  Filter: (client_id = 4242)
     284                                                  Rows Removed by Filter: 83331
     285                                            ->  Index Only Scan using vendor_pkey on vendor v  (actual time=0.011..0.011 rows=1 loops=7)
     286                                                  Index Cond: (vendor_id = cvc.vendor_id)
     287                                      ->  Index Scan using uq_project_contract_name on project p  (actual time=0.021..0.022 rows=7 loops=7)
     288                                            Index Cond: (contract_id = cvc.contract_id)
     289                                ->  Hash  (actual time=0.019..0.019 rows=6 loops=3)
     290                                      [...]
     291              ->  Materialize  (actual time=0.001..0.001 rows=1 loops=52)
     292                    [...]
     293Execution Time: 15.248 ms
     294}}}
     295
     296Без филтер (ист план со и без индексите):
     297
     298{{{
     299Sort  (actual time=1664.838..1669.234 rows=81810 loops=1)
     300  Sort Key: c.company_name, cvc.currency_code
     301  ->  HashAggregate  (actual time=1491.535..1523.486 rows=81810 loops=1)
     302        Group Key: cvc.currency_code, c.client_id
     303        ->  Hash Join  (actual time=70.462..1108.790 rows=1400000 loops=1)
     304              Hash Cond: (p.status_id = ps.status_id)
     305              ->  Hash Join  (actual time=70.445..927.241 rows=1400000 loops=1)
     306                    Hash Cond: (cvc.vendor_id = v.vendor_id)
     307                    ->  Hash Join  (actual time=69.670..726.839 rows=1400000 loops=1)
     308                          Hash Cond: (cvc.client_id = c.client_id)
     309                          ->  Hash Join  (actual time=66.014..486.544 rows=1400000 loops=1)
     310                                Hash Cond: (p.contract_id = cvc.contract_id)
     311                                ->  Seq Scan on project p  (actual time=0.005..92.911 rows=1400000 loops=1)
     312                                ->  Hash  (actual time=65.901..65.903 rows=250000 loops=1)
     313                                      ->  Seq Scan on client_vendor_contract cvc  (actual time=0.004..32.272 rows=250000 loops=1)
     314                          ->  Hash  (actual time=3.641..3.642 rows=20000 loops=1)
     315                                [...]
     316                    ->  Hash  (actual time=0.770..0.770 rows=5000 loops=1)
     317                          [...]
     318              ->  Hash  (actual time=0.011..0.012 rows=6 loops=1)
     319                    [...]
     320Execution Time: 1672.542 ms
     321}}}
     322
     323'''4.''' Индексирање: `idx_cvc_client_id`; агрегацијата по валута потоа работи врз 52 редици.
     324
     325{{{
     326Sort  (actual time=0.134..0.136 rows=3 loops=1)
     327  Sort Key: c.company_name, cvc.currency_code
     328  ->  GroupAggregate  (actual time=0.120..0.129 rows=3 loops=1)
     329        Group Key: cvc.currency_code
     330        ->  Sort  (actual time=0.114..0.117 rows=52 loops=1)
     331              Sort Key: cvc.currency_code
     332              ->  Nested Loop  (actual time=0.040..0.103 rows=52 loops=1)
     333                    ->  Nested Loop  (actual time=0.033..0.079 rows=52 loops=1)
     334                          ->  Nested Loop  (actual time=0.025..0.041 rows=7 loops=1)
     335                                ->  Nested Loop  (actual time=0.020..0.027 rows=7 loops=1)
     336                                      ->  Index Scan using client_pkey on client c  (actual time=0.007..0.008 rows=1 loops=1)
     337                                            Index Cond: (client_id = 4242)
     338                                      ->  Bitmap Heap Scan on client_vendor_contract cvc  (actual time=0.011..0.017 rows=7 loops=1)
     339                                            Recheck Cond: (client_id = 4242)
     340                                            ->  Bitmap Index Scan on idx_cvc_client_id  (actual time=0.007..0.007 rows=7 loops=1)
     341                                                  Index Cond: (client_id = 4242)
     342                                ->  Index Only Scan using vendor_pkey on vendor v  (actual time=0.002..0.002 rows=1 loops=7)
     343                                      Index Cond: (vendor_id = cvc.vendor_id)
     344                          ->  Index Scan using uq_project_contract_name on project p  (actual time=0.003..0.004 rows=7 loops=7)
     345                                Index Cond: (contract_id = cvc.contract_id)
     346                    ->  Memoize  (actual time=0.000..0.000 rows=1 loops=52)
     347                          [...]
     348Execution Time: 0.162 ms
     349}}}
     350
     351'''5.''' Време на извршување:
     352
     353||= Читање =||= Без индексите =||= Со индексите =||= Забрзување =||
     354|| филтрирано по клиент (3 редици) || 16,1 ms || 0,14 ms || 114 пати ||
     355|| нефилтрирано (81.810 редици) || 1,68 s || 1,63 s || ист план ||
     356
     357'''6.''' Времето на извршување на операциите insert и update врз табелите на погледот е во табелата [#write-cost „Цена при запишување“] на почетокот на страницата.
     358
     359----
     360
     361== Поглед 7: Клиенти по индустрија (vw_clients_per_industry) ==
     362
     363'''1.''' Примарен филтер за погледот `vw_clients_per_industry` ќе биде според `industry_id` на индустријата.
     364
     365'''2.''' Примарен случај на употреба ќе биде преглед на сите клиенти од одредена индустрија.
     366
     367'''3.''' Иницијална состојба: главната операција е sequential scan на табелата `Client` (209 страници, 1,7 MB), по што следат поврзувањето со `Industry` и сортирањето; времето е прифатливо за апликацијата.
     368
     369{{{
     370Sort  (actual time=2.515..2.549 rows=968 loops=1)
     371  Sort Key: i.industry_name, c.company_name
     372  ->  Nested Loop  (actual time=0.013..1.203 rows=968 loops=1)
     373        ->  Seq Scan on industry i  (actual time=0.005..0.006 rows=1 loops=1)
     374              Filter: (industry_id = 7)
     375              Rows Removed by Filter: 19
     376        ->  Seq Scan on client c  (actual time=0.007..1.095 rows=968 loops=1)
     377              Filter: (industry_id = 7)
     378              Rows Removed by Filter: 19032
     379Execution Time: 2.599 ms
     380}}}
     381
     382'''4.''' Тестиран е индекс `idx_client_industry_id ON Client (industry_id)`; 968-те клиенти на една индустрија (5 % од табелата) се распоредени низ речиси сите страници, па и со индексот речиси сите страници пак се читаат; добивката е мала и индексот не е креиран. Нема потреба да се преуреди прашалникот.
     383
     384'''5.''' Време на извршување:
     385
     386||= Читање =||= Без индекс =||= Со тестираниот `idx_client_industry_id` =||= Забрзување =||
     387|| филтрирано по индустрија (968 редици) || 2,65 ms || 1,75 ms || 1,5 пати ||
     388|| нефилтрирано (20.000 редици) || 39,1 ms || не е мерено || ||
     389
     390'''6.''' Времето на извршување на операциите insert и update останува исто; врз табелата `Client` нема индекси од оваа фаза.
     391
     392----
     393
     394== Поглед 8: Просечна оценка по софтверска агенција (vw_avg_rating_per_vendor) ==
     395
     396'''1.''' Примарен филтер за погледот `vw_avg_rating_per_vendor` ќе биде според `vendor_id` на софтверската агенција; за јавната ранг-листа се чита и без филтер.
     397
     398'''2.''' Примарен случај на употреба ќе биде приказ на просечната оценка на агенцијата на нејзиниот профил и ранг-листата на сите агенции. Овој поглед е аналитички (агрегира 10.000.000 оценки), па за нефилтрираното читање индексите не помагаат.
     399
     400'''3.''' Иницијална состојба: најбавните операции се сортирањето на 1.000.000 парови (агенција, рецензија), кое `COUNT(DISTINCT r.review_id)` го бара пред агрегирањето, и читањето на сите 10.000.000 оценки од `Review_Score` по рецензија, вклучително и оценките на необјавените рецензии. Првобитната дефиниција:
     401
     402{{{#!sql
     403CREATE OR REPLACE VIEW vw_avg_rating_per_vendor AS
     404SELECT v.vendor_id,
     405       v.agency_name,
     406       COUNT(DISTINCT r.review_id)   AS review_count,  -- DISTINCT бара сортиран влез
     407       ROUND(AVG(rs.score_value), 2) AS avg_rating     -- сите оценки, и на необјавени рецензии
     408FROM Review_Score rs
     409         JOIN Review r ON r.review_id = rs.review_id
     410         JOIN Project p ON p.project_id = r.project_id
     411         JOIN Client_Vendor_Contract cvc ON cvc.contract_id = p.contract_id
     412         JOIN Vendor v ON v.vendor_id = cvc.vendor_id
     413GROUP BY v.vendor_id, v.agency_name
     414ORDER BY avg_rating DESC NULLS LAST;
     415}}}
     416
     417{{{
     418Sort  (actual time=5017.736..5025.135 rows=5000 loops=1)
     419  Sort Key: (round(avg(rs.score_value), 2)) DESC NULLS LAST
     420  ->  GroupAggregate  (actual time=762.816..5021.663 rows=5000 loops=1)
     421        Group Key: v.vendor_id
     422        ->  Nested Loop  (actual time=761.859..4450.418 rows=10000000 loops=1)
     423              ->  Gather Merge  (actual time=761.803..936.599 rows=1000000 loops=1)
     424                    Workers Launched: 2
     425                    ->  Sort  (actual time=742.829..774.390 rows=333333 loops=3)
     426                          Sort Key: v.vendor_id, r.review_id
     427                          ->  Hash Join  (actual time=364.168..632.521 rows=333333 loops=3)
     428                                Hash Cond: (cvc.vendor_id = v.vendor_id)
     429                                [...]
     430              ->  Index Scan using review_score_pkey on review_score rs  (actual time=0.002..0.003 rows=10 loops=1000000)
     431                    Index Cond: (review_id = r.review_id)
     432Execution Time: 5028.229 ms
     433}}}
     434
     435'''4.''' Преуредување на прашалникот, со промена на резултатот: се бројат само објавени рецензии (659.458 од 1.000.000), а `LEFT JOIN` од `Vendor` ги задржува и агенциите без рецензија. Оценките прво се собираат по рецензија (`score_sum`, `score_cnt`), а просекот на агенцијата е `SUM(score_sum) / SUM(score_cnt)`, што е истиот просек како `AVG` врз сите оценки, но без `COUNT(DISTINCT)`, па двете агрегации се хеширани. Филтрирано по агенција, оптимизаторот го спушта условот во потпрашалникот и преку `idx_cvc_vendor_id` ги чита само нејзините рецензии; без филтер `Review_Score` се чита целосно во двата случаја.
     436
     437{{{#!sql
     438CREATE OR REPLACE VIEW vw_avg_rating_per_vendor AS
     439SELECT v.vendor_id,
     440       v.agency_name,
     441       COUNT(vr.review_id)                                        AS review_count,
     442       -- просек на сите оценки на агенцијата; NULLIF штити од делење со нула
     443       ROUND(SUM(vr.score_sum) / NULLIF(SUM(vr.score_cnt), 0), 2) AS avg_rating
     444FROM Vendor v
     445         -- LEFT JOIN: агенција без објавена рецензија останува со review_count = 0
     446         -- потпрашалник: збир и број на оценки по рецензија, само објавени рецензии
     447         LEFT JOIN (SELECT pd.vendor_id,
     448                           r.review_id,
     449                           SUM(rs.score_value)::numeric AS score_sum,
     450                           COUNT(*)                     AS score_cnt
     451                    FROM Review r
     452                             JOIN Review_Score rs ON rs.review_id = r.review_id
     453                             JOIN vw_project_details pd ON pd.project_id = r.project_id
     454                    WHERE r.is_published = true
     455                    GROUP BY pd.vendor_id, r.review_id) vr ON vr.vendor_id = v.vendor_id
     456GROUP BY v.vendor_id, v.agency_name
     457ORDER BY avg_rating DESC NULLS LAST;
     458}}}
     459
     460Без филтер:
     461
     462{{{
     463Sort  (actual time=4183.548..4183.741 rows=5000 loops=1)
     464  Sort Key: (round((sum(((sum(rs.score_value))::numeric)) / NULLIF(sum((count(*))), '0'::numeric)), 2)) DESC NULLS LAST
     465  ->  HashAggregate  (actual time=4179.979..4181.793 rows=5000 loops=1)
     466        Group Key: v.vendor_id
     467        ->  Hash Right Join  (actual time=3831.864..4079.611 rows=659458 loops=1)
     468              Hash Cond: (v_1.vendor_id = v.vendor_id)
     469              ->  HashAggregate  (actual time=3617.949..3787.674 rows=659458 loops=1)
     470                    Group Key: v_1.vendor_id, r.review_id
     471                    ->  Hash Join  (actual time=1209.193..2820.624 rows=6594580 loops=1)
     472                          Hash Cond: (rs.review_id = r.review_id)
     473                          ->  Seq Scan on review_score rs  (actual time=0.041..458.448 rows=10000000 loops=1)
     474                          ->  Hash  (actual time=1205.593..1205.600 rows=659458 loops=1)
     475                                [...]
     476              ->  Hash  (actual time=213.903..213.903 rows=5000 loops=1)
     477                    [...]
     478Execution Time: 4219.610 ms
     479}}}
     480
     481Филтрирано по софтверска агенција, со индексите:
     482
     483{{{
     484Sort  (actual time=1.615..1.617 rows=1 loops=1)
     485  Sort Key: (round((sum(((sum(rs.score_value))::numeric)) / NULLIF(sum((count(*))), '0'::numeric)), 2)) DESC NULLS LAST
     486  ->  GroupAggregate  (actual time=1.611..1.613 rows=1 loops=1)
     487        ->  Nested Loop Left Join  (actual time=1.569..1.600 rows=123 loops=1)
     488              ->  Index Scan using vendor_pkey on vendor v  (actual time=0.006..0.007 rows=1 loops=1)
     489                    Index Cond: (vendor_id = 4242)
     490              ->  HashAggregate  (actual time=1.562..1.584 rows=123 loops=1)
     491                    Group Key: r.review_id
     492                    ->  Nested Loop  (actual time=0.080..1.420 rows=1230 loops=1)
     493                          ->  Nested Loop  (actual time=0.075..0.881 rows=123 loops=1)
     494                                Join Filter: (ps.status_id = p.status_id)
     495                                Rows Removed by Join Filter: 369
     496                                ->  Nested Loop  (actual time=0.066..0.814 rows=123 loops=1)
     497                                      ->  Nested Loop  (actual time=0.033..0.385 rows=276 loops=1)
     498                                            ->  Nested Loop  (actual time=0.025..0.155 rows=47 loops=1)
     499                                                  [...]
     500                                                  ->  Nested Loop  (actual time=0.021..0.146 rows=47 loops=1)
     501                                                        ->  Bitmap Heap Scan on client_vendor_contract cvc  (actual time=0.015..0.062 rows=47 loops=1)
     502                                                              Recheck Cond: (vendor_id = 4242)
     503                                                              ->  Bitmap Index Scan on idx_cvc_vendor_id  (actual time=0.005..0.005 rows=47 loops=1)
     504                                                                    Index Cond: (vendor_id = 4242)
     505                                                        ->  Index Only Scan using client_pkey on client c  (actual time=0.001..0.001 rows=1 loops=47)
     506                                                              Index Cond: (client_id = cvc.client_id)
     507                                            ->  Index Scan using uq_project_contract_name on project p  (actual time=0.003..0.004 rows=6 loops=47)
     508                                                  Index Cond: (contract_id = cvc.contract_id)
     509                                      ->  Index Scan using review_project_id_key on review r  (actual time=0.001..0.001 rows=0 loops=276)
     510                                            Index Cond: (project_id = p.project_id)
     511                                            Filter: is_published
     512                                            Rows Removed by Filter: 0
     513                                ->  Materialize  (actual time=0.000..0.000 rows=4 loops=123)
     514                                      ->  Seq Scan on project_status ps  (actual time=0.005..0.006 rows=4 loops=1)
     515                          ->  Index Scan using review_score_pkey on review_score rs  (actual time=0.002..0.003 rows=10 loops=123)
     516                                Index Cond: (review_id = r.review_id)
     517Execution Time: 1.671 ms
     518}}}
     519
     520'''5.''' Време на извршување:
     521
     522Првобитната и новата дефиниција не даваат ист резултат; табелата споредува два различни прашалници.
     523
     524||= Читање =||= Првобитна, без индексите =||= Првобитна, со индексите =||= Нова, без индексите =||= Нова, со индексите =||
     525|| филтрирано по софтверска агенција (1 редица) || 16,2 ms || 2,06 ms || 14,0 ms || 1,90 ms ||
     526|| нефилтрирано (5.000 редици) || 4,97 s || 5,11 s || 4,19 s || 4,35 s ||
     527
     528'''6.''' Времето на извршување на операциите insert и update врз табелите на погледот е во табелата [#write-cost „Цена при запишување“] на почетокот на страницата.
     529
     530----
     531
     532== Поглед 9: Нерешени спорови (vw_unresolved_dispute_tickets) ==
     533
     534'''1.''' Примарен филтер за погледот `vw_unresolved_dispute_tickets` ќе биде според `project_id` на проектот или `vendor_id` на софтверската агенција; менаџментот го чита и без филтер, како ред на задачи.
     535
     536'''2.''' Примарен случај на употреба ќе биде преглед на отворените спорови за еден проект или една агенција и редот на нерешени спорови за менаџментот. Перформансите на овој поглед се важни, бидејќи се чита при секоја работа со спорови.
     537
     538'''3.''' Иницијална состојба: најбавната операција не е sequential scan, туку функцијата `fn_get_full_name()`, повикана двапати по редица за имињата на поднесувачот и на доделениот менаџмент корисник: 58.002 извршени повици, секој посебен прашалник врз `"User"` (вториот повик добива NULL за недоделен спор, а функцијата е STRICT и тогаш не се извршува). Повикот на функција во листата на колони го спречува и паралелното извршување. Првобитната дефиниција:
     539
     540{{{#!sql
     541CREATE OR REPLACE VIEW vw_unresolved_dispute_tickets AS
     542SELECT dt.ticket_id,
     543       dt.filed_at,
     544       dt.reason,
     545       r.review_id,
     546       p.project_id,
     547       p.project_name,
     548       vu.user_id                               AS filed_by_vendor_user_id,
     549       fn_get_full_name(vu.user_id)    AS filed_by_vendor_user,          -- повик по редица
     550       mu.user_id                               AS assigned_management_user_id,
     551       fn_get_full_name(mu.user_id)    AS assigned_to_management_user,   -- повик по редица
     552       dt.created_at,
     553       dt.updated_at
     554FROM Dispute_Ticket dt
     555         JOIN Review r ON r.review_id = dt.review_id
     556         JOIN Project p ON p.project_id = r.project_id
     557         JOIN Vendor_User vu ON vu.user_id = dt.vendor_user_id
     558         LEFT JOIN Management_User mu ON mu.user_id = dt.assigned_management_user_id
     559WHERE dt.is_resolved = false
     560ORDER BY dt.filed_at;
     561}}}
     562
     563{{{
     564Sort  (actual time=781.820..788.679 rows=58002 loops=1)
     565  Sort Key: dt.filed_at
     566  ->  Hash Left Join  (actual time=38.322..751.524 rows=58002 loops=1)
     567        Hash Cond: (dt.assigned_management_user_id = mu.user_id)
     568        ->  Hash Join  (actual time=37.851..471.846 rows=58002 loops=1)
     569              Hash Cond: (dt.vendor_user_id = vu.user_id)
     570              ->  Nested Loop  (actual time=24.480..434.236 rows=58002 loops=1)
     571                    ->  Hash Join  (actual time=24.459..318.522 rows=58002 loops=1)
     572                          Hash Cond: (r.review_id = dt.review_id)
     573                          ->  Seq Scan on review r  (actual time=0.009..66.118 rows=1000000 loops=1)
     574                          ->  Hash  (actual time=24.391..24.392 rows=58002 loops=1)
     575                                [...]
     576                    ->  Index Scan using project_pkey on project p  (actual time=0.002..0.002 rows=1 loops=58002)
     577                          Index Cond: (project_id = r.project_id)
     578              ->  Hash  (actual time=13.353..13.354 rows=25000 loops=1)
     579                    [...]
     580        ->  Hash  (actual time=0.318..0.318 rows=2000 loops=1)
     581              [...]
     582Execution Time: 792.358 ms
     583}}}
     584
     585'''4.''' Преуредување на прашалникот: имињата се добиваат со две поврзувања со `"User"` наместо со повици на функција, поврзувањето со `Management_User` е отстрането (надворешниот клуч гарантира дека доделениот корисник е менаџмент корисник), а додадени се колоните `vendor_id` и `agency_name` за филтрирање по агенција. Планот без филтер е паралелен; филтрирано по проект се чита преку уникатниот индекс `review_project_id_key` и делумниот уникатен индекс `uq_dispute_open_per_vendor_review` од шемата. Дополнителен индекс не го подобрува планот на овој поглед: условот `is_resolved = false` избира 40 % од табелата, па индекс врз таа колона не би се користел.
     586
     587{{{#!sql
     588CREATE VIEW vw_unresolved_dispute_tickets AS
     589SELECT dt.ticket_id,
     590       dt.filed_at,
     591       dt.reason,
     592       r.review_id,
     593       p.project_id,
     594       p.project_name,
     595       dt.vendor_user_id                        AS filed_by_vendor_user_id,
     596       -- имињата на поднесувачот (vusr) и на доделениот корисник (musr) од две
     597       -- поврзувања со "User"; musr е NULL додека спорот не е доделен (LEFT JOIN)
     598       vusr.first_name || ' ' || vusr.last_name AS filed_by_vendor_user,
     599       dt.assigned_management_user_id,
     600       musr.first_name || ' ' || musr.last_name AS assigned_to_management_user,
     601       dt.created_at,
     602       dt.updated_at,
     603       ven.vendor_id,
     604       ven.agency_name
     605FROM Dispute_Ticket dt
     606         JOIN Review r ON r.review_id = dt.review_id
     607         JOIN Project p ON p.project_id = r.project_id
     608         JOIN Vendor_User vu ON vu.user_id = dt.vendor_user_id
     609         JOIN Vendor ven ON ven.vendor_id = vu.vendor_id
     610         JOIN "User" vusr ON vusr.user_id = vu.user_id
     611         LEFT JOIN "User" musr ON musr.user_id = dt.assigned_management_user_id
     612WHERE dt.is_resolved = false
     613ORDER BY dt.filed_at;
     614}}}
     615
     616Без филтер:
     617
     618{{{
     619Gather Merge  (actual time=194.937..215.581 rows=58002 loops=1)
     620  Workers Launched: 2
     621  ->  Sort  (actual time=191.770..193.702 rows=19334 loops=3)
     622        Sort Key: dt.filed_at
     623        ->  Nested Loop Left Join  (actual time=37.737..182.784 rows=19334 loops=3)
     624              ->  Nested Loop  (actual time=37.661..174.551 rows=19334 loops=3)
     625                    [...]
     626                    ->  Index Scan using project_pkey on project p  (actual time=0.002..0.002 rows=1 loops=58002)
     627                          Index Cond: (project_id = r.project_id)
     628              ->  Memoize  (actual time=0.000..0.000 rows=0 loops=58002)
     629                    [...]
     630Execution Time: 217.633 ms
     631}}}
     632
     633Филтрирано по проект:
     634
     635{{{
     636Sort  (actual time=0.034..0.035 rows=1 loops=1)
     637  Sort Key: dt.filed_at
     638  ->  Nested Loop Left Join  (actual time=0.030..0.032 rows=1 loops=1)
     639        ->  Nested Loop  (actual time=0.027..0.030 rows=1 loops=1)
     640              ->  Nested Loop  (actual time=0.025..0.027 rows=1 loops=1)
     641                    ->  Nested Loop  (actual time=0.022..0.023 rows=1 loops=1)
     642                          ->  Nested Loop  (actual time=0.018..0.019 rows=1 loops=1)
     643                                ->  Nested Loop  (actual time=0.013..0.014 rows=1 loops=1)
     644                                      ->  Index Scan using review_project_id_key on review r  (actual time=0.008..0.008 rows=1 loops=1)
     645                                            Index Cond: (project_id = 142160)
     646                                      ->  Index Scan using uq_dispute_open_per_vendor_review on dispute_ticket dt  (actual time=0.004..0.004 rows=1 loops=1)
     647                                            Index Cond: (review_id = r.review_id)
     648                                ->  Index Scan using project_pkey on project p  (actual time=0.004..0.005 rows=1 loops=1)
     649                                      Index Cond: (project_id = 142160)
     650                          ->  Index Scan using "User_pkey" on "User" vusr  (actual time=0.003..0.003 rows=1 loops=1)
     651                                Index Cond: (user_id = dt.vendor_user_id)
     652                    ->  Index Scan using vendor_user_pkey on vendor_user vu  (actual time=0.003..0.003 rows=1 loops=1)
     653                          Index Cond: (user_id = dt.vendor_user_id)
     654              ->  Index Scan using vendor_pkey on vendor ven  (actual time=0.002..0.002 rows=1 loops=1)
     655                    Index Cond: (vendor_id = vu.vendor_id)
     656        ->  Index Scan using "User_pkey" on "User" musr  (actual time=0.000..0.000 rows=0 loops=1)
     657              Index Cond: (user_id = dt.assigned_management_user_id)
     658Execution Time: 0.062 ms
     659}}}
     660
     661'''5.''' Време на извршување:
     662
     663||= Читање =||= Првобитна дефиниција =||= Нова дефиниција =||= Забрзување =||
     664|| филтрирано по проект (1 редица) || 0,10 ms || 0,06 ms || 1,8 пати ||
     665|| нефилтрирано (58.002 редици) || 689 ms || 210 ms || 3,3 пати ||
     666
     667'''6.''' Времето на извршување на операциите insert и update врз табелата `Dispute_Ticket` е во табелата [#write-cost „Цена при запишување“] на почетокот на страницата.
     668
     669----
     670
     671== Поглед 10: Број на проекти по статус по софтверска агенција (vw_project_count_by_status_per_vendor) ==
     672
     673'''1.''' Примарен филтер за погледот `vw_project_count_by_status_per_vendor` ќе биде според `vendor_id` на софтверската агенција.
     674
     675'''2.''' Примарен случај на употреба ќе биде преглед на бројот на проекти на агенцијата по статус, на нејзината контролна табла. Погледот е аналитички (`COUNT`, `GROUP BY`).
     676
     677'''3.''' Иницијална состојба: филтрирано, најбавната операција е sequential scan на `Client_Vendor_Contract`; нефилтрирано, планот е hash join на sequential scan на табелите со агрегација (`HashAggregate`), кај кој индексите не помагаат.
     678
     679{{{
     680Sort  (actual time=11.804..15.019 rows=6 loops=1)
     681  Sort Key: v.agency_name, ps.status_name
     682  ->  GroupAggregate  (actual time=11.645..15.008 rows=6 loops=1)
     683        Group Key: ps.status_name, p.status_id
     684        ->  Incremental Sort  (actual time=11.571..14.973 rows=276 loops=1)
     685              Sort Key: ps.status_name, p.status_id
     686              ->  Nested Loop  (actual time=0.954..14.889 rows=276 loops=1)
     687                    Join Filter: (ps.status_id = p.status_id)
     688                    Rows Removed by Join Filter: 1380
     689                    ->  Index Scan using project_status_status_name_key on project_status ps  (actual time=0.006..0.009 rows=6 loops=1)
     690                    ->  Materialize  (actual time=0.158..2.461 rows=276 loops=6)
     691                          ->  Nested Loop  (actual time=0.943..14.647 rows=276 loops=1)
     692                                ->  Index Scan using vendor_pkey on vendor v  (actual time=0.010..0.012 rows=1 loops=1)
     693                                      Index Cond: (vendor_id = 4242)
     694                                ->  Gather  (actual time=0.932..14.598 rows=276 loops=1)
     695                                      Workers Launched: 2
     696                                      ->  Nested Loop  (actual time=0.470..9.084 rows=92 loops=3)
     697                                            ->  Nested Loop  (actual time=0.445..8.875 rows=16 loops=3)
     698                                                  ->  Parallel Seq Scan on client_vendor_contract cvc  (actual time=0.428..8.784 rows=16 loops=3)
     699                                                        Filter: (vendor_id = 4242)
     700                                                        Rows Removed by Filter: 83318
     701                                                  ->  Index Only Scan using client_pkey on client c  (actual time=0.005..0.005 rows=1 loops=47)
     702                                                        Index Cond: (client_id = cvc.client_id)
     703                                            ->  Index Scan using uq_project_contract_name on project p  (actual time=0.011..0.012 rows=6 loops=47)
     704                                                  Index Cond: (contract_id = cvc.contract_id)
     705Execution Time: 15.056 ms
     706}}}
     707
     708'''4.''' Индексирање: `idx_cvc_vendor_id`; агрегацијата по статус потоа работи врз 276 редици.
     709
     710{{{
     711Sort  (actual time=0.566..0.568 rows=6 loops=1)
     712  Sort Key: v.agency_name, ps.status_name
     713  ->  GroupAggregate  (actual time=0.524..0.561 rows=6 loops=1)
     714        Group Key: ps.status_name, p.status_id
     715        ->  Sort  (actual time=0.518..0.529 rows=276 loops=1)
     716              Sort Key: ps.status_name, p.status_id
     717              ->  Nested Loop  (actual time=0.040..0.461 rows=276 loops=1)
     718                    ->  Nested Loop  (actual time=0.034..0.378 rows=276 loops=1)
     719                          ->  Nested Loop  (actual time=0.027..0.156 rows=47 loops=1)
     720                                ->  Index Scan using vendor_pkey on vendor v  (actual time=0.005..0.006 rows=1 loops=1)
     721                                      Index Cond: (vendor_id = 4242)
     722                                ->  Nested Loop  (actual time=0.021..0.144 rows=47 loops=1)
     723                                      ->  Bitmap Heap Scan on client_vendor_contract cvc  (actual time=0.015..0.063 rows=47 loops=1)
     724                                            Recheck Cond: (vendor_id = 4242)
     725                                            ->  Bitmap Index Scan on idx_cvc_vendor_id  (actual time=0.009..0.009 rows=47 loops=1)
     726                                                  Index Cond: (vendor_id = 4242)
     727                                      ->  Index Only Scan using client_pkey on client c  (actual time=0.001..0.001 rows=1 loops=47)
     728                                            Index Cond: (client_id = cvc.client_id)
     729                          ->  Index Scan using uq_project_contract_name on project p  (actual time=0.003..0.004 rows=6 loops=47)
     730                                Index Cond: (contract_id = cvc.contract_id)
     731                    ->  Memoize  (actual time=0.000..0.000 rows=1 loops=276)
     732                          [...]
     733Execution Time: 0.653 ms
     734}}}
     735
     736'''5.''' Време на извршување:
     737
     738||= Читање =||= Без индексите =||= Со индексите =||= Забрзување =||
     739|| филтрирано по софтверска агенција (6 редици) || 14,9 ms || 0,60 ms || 25 пати ||
     740|| нефилтрирано (29.907 редици) || 1,36 s || 1,32 s || ист план ||
     741
     742'''6.''' Времето на извршување на операциите insert и update врз табелите на погледот е во табелата [#write-cost „Цена при запишување“] на почетокот на страницата.
     743
     744----
     745
     746== Поглед 11: Број на проекти по статус по клиент (vw_project_count_by_status_per_client) ==
     747
     748'''1.''' Примарен филтер за погледот `vw_project_count_by_status_per_client` ќе биде според `client_id` на клиентот.
     749
     750'''2.''' Примарен случај на употреба ќе биде преглед на бројот на проекти на клиентот по статус, на неговата контролна табла. Погледот е аналитички (`COUNT`, `GROUP BY`).
     751
     752'''3.''' Иницијална состојба: филтрирано, најбавната операција е sequential scan на `Client_Vendor_Contract`; нефилтрирано, планот е hash join на sequential scan на табелите со агрегација (`HashAggregate`), кај кој индексите не помагаат.
     753
     754{{{
     755Sort  (actual time=11.627..15.317 rows=5 loops=1)
     756  Sort Key: c.company_name, ps.status_name
     757  ->  GroupAggregate  (actual time=11.591..15.305 rows=5 loops=1)
     758        Group Key: ps.status_name, p.status_id
     759        ->  Incremental Sort  (actual time=11.571..15.279 rows=52 loops=1)
     760              Sort Key: ps.status_name, p.status_id
     761              ->  Nested Loop  (actual time=0.612..15.253 rows=52 loops=1)
     762                    Join Filter: (ps.status_id = p.status_id)
     763                    Rows Removed by Join Filter: 260
     764                    ->  Index Scan using project_status_status_name_key on project_status ps  (actual time=0.007..0.009 rows=6 loops=1)
     765                    ->  Materialize  (actual time=0.100..2.533 rows=52 loops=6)
     766                          ->  Nested Loop  (actual time=0.598..15.170 rows=52 loops=1)
     767                                ->  Index Scan using client_pkey on client c  (actual time=0.008..0.010 rows=1 loops=1)
     768                                      Index Cond: (client_id = 4242)
     769                                ->  Gather  (actual time=0.589..15.151 rows=52 loops=1)
     770                                      Workers Launched: 2
     771                                      ->  Nested Loop  (actual time=3.807..8.919 rows=17 loops=3)
     772                                            ->  Nested Loop  (actual time=3.778..8.856 rows=2 loops=3)
     773                                                  ->  Parallel Seq Scan on client_vendor_contract cvc  (actual time=3.729..8.794 rows=2 loops=3)
     774                                                        Filter: (client_id = 4242)
     775                                                        Rows Removed by Filter: 83331
     776                                                  ->  Index Only Scan using vendor_pkey on vendor v  (actual time=0.023..0.023 rows=1 loops=7)
     777                                                        Index Cond: (vendor_id = cvc.vendor_id)
     778                                            ->  Index Scan using uq_project_contract_name on project p  (actual time=0.023..0.025 rows=7 loops=7)
     779                                                  Index Cond: (contract_id = cvc.contract_id)
     780Execution Time: 15.362 ms
     781}}}
     782
     783'''4.''' Индексирање: `idx_cvc_client_id`; агрегацијата по статус потоа работи врз 52 редици.
     784
     785{{{
     786Sort  (actual time=0.122..0.124 rows=5 loops=1)
     787  Sort Key: c.company_name, ps.status_name
     788  ->  GroupAggregate  (actual time=0.111..0.120 rows=5 loops=1)
     789        Group Key: ps.status_name, p.status_id
     790        ->  Sort  (actual time=0.108..0.111 rows=52 loops=1)
     791              Sort Key: ps.status_name, p.status_id
     792              ->  Nested Loop  (actual time=0.038..0.097 rows=52 loops=1)
     793                    ->  Nested Loop  (actual time=0.030..0.071 rows=52 loops=1)
     794                          ->  Nested Loop  (actual time=0.026..0.040 rows=7 loops=1)
     795                                ->  Nested Loop  (actual time=0.018..0.025 rows=7 loops=1)
     796                                      ->  Index Scan using client_pkey on client c  (actual time=0.005..0.006 rows=1 loops=1)
     797                                            Index Cond: (client_id = 4242)
     798                                      ->  Bitmap Heap Scan on client_vendor_contract cvc  (actual time=0.012..0.017 rows=7 loops=1)
     799                                            Recheck Cond: (client_id = 4242)
     800                                            ->  Bitmap Index Scan on idx_cvc_client_id  (actual time=0.008..0.008 rows=7 loops=1)
     801                                                  Index Cond: (client_id = 4242)
     802                                ->  Index Only Scan using vendor_pkey on vendor v  (actual time=0.002..0.002 rows=1 loops=7)
     803                                      Index Cond: (vendor_id = cvc.vendor_id)
     804                          ->  Index Scan using uq_project_contract_name on project p  (actual time=0.003..0.003 rows=7 loops=7)
     805                                Index Cond: (contract_id = cvc.contract_id)
     806                    ->  Memoize  (actual time=0.000..0.000 rows=1 loops=52)
     807                          [...]
     808Execution Time: 0.148 ms
     809}}}
     810
     811'''5.''' Време на извршување:
     812
     813||= Читање =||= Без индексите =||= Со индексите =||= Забрзување =||
     814|| филтрирано по клиент (5 редици) || 15,4 ms || 0,13 ms || 115 пати ||
     815|| нефилтрирано (103.080 редици) || 1,55 s || 1,56 s || ист план ||
     816
     817'''6.''' Времето на извршување на операциите insert и update врз табелите на погледот е во табелата [#write-cost „Цена при запишување“] на почетокот на страницата.
     818
     819----
     820
     821== Поглед 12: Договори по софтверска агенција (vw_contracts_per_vendor) ==
     822
     823'''1.''' Примарен филтер за погледот `vw_contracts_per_vendor` ќе биде според `vendor_id` на софтверската агенција.
     824
     825'''2.''' Примарен случај на употреба ќе биде преглед на сите активни и историски договори на одредена софтверска агенција. Перформансите на овој поглед се важни, бидејќи се чита при секое отворање на профилот на агенцијата.
     826
     827'''3.''' Иницијална состојба: најбавната операција е sequential scan на табелата `Client_Vendor_Contract` (250.000 редици, 5.652 страници), паралелен, со отфрлање на 249.953 редици.
     828
     829{{{
     830Sort  (actual time=11.459..15.086 rows=47 loops=1)
     831  Sort Key: v.agency_name, cvc.is_active DESC, cvc.start_date DESC
     832  ->  Nested Loop  (actual time=0.870..15.011 rows=47 loops=1)
     833        ->  Index Scan using vendor_pkey on vendor v  (actual time=0.006..0.008 rows=1 loops=1)
     834              Index Cond: (vendor_id = 4242)
     835        ->  Gather  (actual time=0.863..14.992 rows=47 loops=1)
     836              Workers Launched: 2
     837              ->  Nested Loop  (actual time=0.414..8.904 rows=16 loops=3)
     838                    ->  Parallel Seq Scan on client_vendor_contract cvc  (actual time=0.389..8.749 rows=16 loops=3)
     839                          Filter: (vendor_id = 4242)
     840                          Rows Removed by Filter: 83318
     841                    ->  Index Scan using client_pkey on client c  (actual time=0.009..0.009 rows=1 loops=47)
     842                          Index Cond: (client_id = cvc.client_id)
     843Execution Time: 15.108 ms
     844}}}
     845
     846'''4.''' Индексирање: `idx_cvc_vendor_id`; наместо sequential scan на 5.652 страници се читаат неколку страници од индексот и по една страница за секој од 47-те договори.
     847
     848{{{
     849Sort  (actual time=0.204..0.217 rows=47 loops=1)
     850  Sort Key: v.agency_name, cvc.is_active DESC, cvc.start_date DESC
     851  ->  Nested Loop  (actual time=0.020..0.147 rows=47 loops=1)
     852        ->  Index Scan using vendor_pkey on vendor v  (actual time=0.005..0.005 rows=1 loops=1)
     853              Index Cond: (vendor_id = 4242)
     854        ->  Nested Loop  (actual time=0.014..0.136 rows=47 loops=1)
     855              ->  Bitmap Heap Scan on client_vendor_contract cvc  (actual time=0.010..0.046 rows=47 loops=1)
     856                    Recheck Cond: (vendor_id = 4242)
     857                    ->  Bitmap Index Scan on idx_cvc_vendor_id  (actual time=0.004..0.004 rows=47 loops=1)
     858                          Index Cond: (vendor_id = 4242)
     859              ->  Index Scan using client_pkey on client c  (actual time=0.002..0.002 rows=1 loops=47)
     860                    Index Cond: (client_id = cvc.client_id)
     861Execution Time: 0.238 ms
     862}}}
     863
     864'''5.''' Време на извршување:
     865
     866||= Читање =||= Без индексите =||= Со индексите =||= Забрзување =||
     867|| филтрирано по софтверска агенција (47 редици) || 15,0 ms || 0,28 ms || 53 пати ||
     868|| нефилтрирано (250.000 редици) || 819 ms || 808 ms || ист план ||
     869
     870'''6.''' Времето на извршување на операциите insert и update врз табелите на погледот е во табелата [#write-cost „Цена при запишување“] на почетокот на страницата.
     871
     872----
     873
     874== Поглед 13: Договори по клиент (vw_contracts_per_client) ==
     875
     876'''1.''' Примарен филтер за погледот `vw_contracts_per_client` ќе биде според `client_id` на клиентот.
     877
     878'''2.''' Примарен случај на употреба ќе биде преглед на сите активни и историски договори на одреден клиент, на контролната табла на клиентот.
     879
     880'''3.''' Иницијална состојба: најбавната операција е sequential scan на табелата `Client_Vendor_Contract` со филтер по `client_id`, со отфрлање на 249.993 редици.
     881
     882{{{
     883Gather Merge  (actual time=10.854..14.183 rows=7 loops=1)
     884  Workers Launched: 2
     885  ->  Sort  (actual time=8.551..8.553 rows=2 loops=3)
     886        Sort Key: c.company_name, cvc.is_active DESC, cvc.start_date DESC
     887        ->  Nested Loop  (actual time=3.035..8.512 rows=2 loops=3)
     888              ->  Nested Loop  (actual time=3.020..8.486 rows=2 loops=3)
     889                    ->  Parallel Seq Scan on client_vendor_contract cvc  (actual time=3.001..8.459 rows=2 loops=3)
     890                          Filter: (client_id = 4242)
     891                          Rows Removed by Filter: 83331
     892                    ->  Index Scan using client_pkey on client c  (actual time=0.009..0.010 rows=1 loops=7)
     893                          Index Cond: (client_id = 4242)
     894              ->  Index Scan using vendor_pkey on vendor v  (actual time=0.010..0.010 rows=1 loops=7)
     895                    Index Cond: (vendor_id = cvc.vendor_id)
     896Execution Time: 14.209 ms
     897}}}
     898
     899'''4.''' Индексирање: `idx_cvc_client_id`. Колоната `client_id` има 20.000 различни вредности, просечно 12,5 договори по клиент, па е поселективна од `vendor_id` (5.000 вредности, 50 договори по агенција).
     900
     901{{{
     902Sort  (actual time=0.066..0.067 rows=7 loops=1)
     903  Sort Key: c.company_name, cvc.is_active DESC, cvc.start_date DESC
     904  ->  Nested Loop  (actual time=0.026..0.041 rows=7 loops=1)
     905        ->  Nested Loop  (actual time=0.019..0.025 rows=7 loops=1)
     906              ->  Index Scan using client_pkey on client c  (actual time=0.007..0.008 rows=1 loops=1)
     907                    Index Cond: (client_id = 4242)
     908              ->  Bitmap Heap Scan on client_vendor_contract cvc  (actual time=0.010..0.014 rows=7 loops=1)
     909                    Recheck Cond: (client_id = 4242)
     910                    ->  Bitmap Index Scan on idx_cvc_client_id  (actual time=0.005..0.005 rows=7 loops=1)
     911                          Index Cond: (client_id = 4242)
     912        ->  Index Scan using vendor_pkey on vendor v  (actual time=0.002..0.002 rows=1 loops=7)
     913              Index Cond: (vendor_id = cvc.vendor_id)
     914Execution Time: 0.113 ms
     915}}}
     916
     917'''5.''' Време на извршување:
     918
     919||= Читање =||= Без индексите =||= Со индексите =||= Забрзување =||
     920|| филтрирано по клиент (7 редици) || 14,2 ms || 0,08 ms || 173 пати ||
     921|| нефилтрирано (250.000 редици) || 817 ms || 805 ms || ист план ||
     922
     923'''6.''' Времето на извршување на операциите insert и update врз табелите на погледот е во табелата [#write-cost „Цена при запишување“] на почетокот на страницата.
     924
     925----
     926
     927== Поглед 14: Претплати на софтверски агенции (vw_vendor_subscriptions) ==
     928
     929'''1.''' Примарен филтер за погледот `vw_vendor_subscriptions` ќе биде според `vendor_id` на софтверската агенција.
     930
     931'''2.''' Примарен случај на употреба ќе биде преглед на активните и историските претплати на одредена софтверска агенција.
     932
     933'''3.''' Иницијална состојба: главната операција е sequential scan на табелата `Vendor_Subscription` (5.916 редици на 57 страници) со отфрлање на 5.914 редици; времето е прифатливо за апликацијата.
     934
     935{{{
     936Sort  (actual time=0.333..0.334 rows=2 loops=1)
     937  Sort Key: v.agency_name, vs.is_active DESC, vs.start_date DESC
     938  ->  Nested Loop  (actual time=0.279..0.328 rows=2 loops=1)
     939        Join Filter: (st.tier_id = vs.tier_id)
     940        Rows Removed by Join Filter: 5
     941        ->  Nested Loop  (actual time=0.276..0.323 rows=2 loops=1)
     942              ->  Seq Scan on vendor_subscription vs  (actual time=0.270..0.315 rows=2 loops=1)
     943                    Filter: (vendor_id = 4242)
     944                    Rows Removed by Filter: 5914
     945              ->  Index Scan using vendor_pkey on vendor v  (actual time=0.003..0.003 rows=1 loops=2)
     946                    Index Cond: (vendor_id = 4242)
     947        ->  Seq Scan on subscription_tier st  (actual time=0.001..0.001 rows=4 loops=2)
     948Execution Time: 0.347 ms
     949}}}
     950
     951'''4.''' За табела од 456 kB индексот не би донел мерлива добивка; нема потреба да се преуреди прашалникот ниту да се додаде индекс.
     952
     953'''5.''' Време на извршување:
     954
     955||= Читање =||= Време =||
     956|| филтрирано по софтверска агенција (2 редици) || 0,32 ms ||
     957|| нефилтрирано (5.916 редици) || 11,4 ms ||
     958
     959'''6.''' Времето на извршување на операциите insert и update останува исто; врз табелата `Vendor_Subscription` нема индекси од оваа фаза.