| 3 | | == Performance |
| | 3 | == Scenario 1 - Top Selling Products and Restock Plan |
| | 4 | |
| | 5 | ==== Without indexes |
| | 6 | |
| | 7 | The query was tested on approximately 25,017 orders and 75,021 order-product records. Before indexing, PostgreSQL used sequential scans on both {{{orders}}} and {{{order_products}}}. |
| | 8 | |
| | 9 | {{{ |
| | 10 | Seq Scan on order_products |
| | 11 | rows=75021 |
| | 12 | |
| | 13 | Seq Scan on orders |
| | 14 | rows=5009 |
| | 15 | Rows Removed by Filter: 20008 |
| | 16 | }}} |
| | 17 | |
| | 18 | The query was executed 10 times and the average execution time without indexes was: **25.646 ms** |
| | 19 | |
| | 20 | ==== Indexes |
| | 21 | {{{ |
| | 22 | CREATE INDEX idx_orders_status_purchase_date |
| | 23 | ON project.orders (status, purchase_date, order_id); |
| | 24 | |
| | 25 | CREATE INDEX idx_order_products_order_product_quantity |
| | 26 | ON project.order_products (order_id, product_id, quantity); |
| | 27 | |
| | 28 | ANALYZE project.orders; |
| | 29 | ANALYZE project.order_products; |
| | 30 | }}} |
| | 31 | |
| | 32 | * The first index targets the filters on {{{status}}} and {{{purchase_date}}}, while also including {{{order_id}}} for the join. |
| | 33 | |
| | 34 | * The second index was tested to support the join and aggregation on {{{order_products}}}. |
| | 35 | |
| | 36 | ==== With indexes |
| | 37 | |
| | 38 | After indexing, PostgreSQL used: |
| | 39 | |
| | 40 | {{{ |
| | 41 | Index Only Scan using idx_orders_status_purchase_date on orders |
| | 42 | Heap Fetches: 0 |
| | 43 | }}} |
| | 44 | |
| | 45 | This replaced the previous sequential scan on orders. |
| | 46 | |
| | 47 | However, PostgreSQL did not use {{{idx_order_products_order_product_quantity}}}. It continued using: |
| | 48 | |
| | 49 | {{{ |
| | 50 | Seq Scan on order_products |
| | 51 | }}} |
| | 52 | |
| | 53 | because scanning the table and performing a hash join was estimated to be cheaper. |
| | 54 | |
| | 55 | The query was again executed 10 times and the average execution time with indexes was: **22.299 ms** |
| | 56 | |
| | 57 | ==== Performance comparison and conclusion |
| | 58 | {{{ |
| | 59 | Without indexes: 25.646 ms |
| | 60 | With indexes: 22.299 ms |
| | 61 | Improvement: 13.05% |
| | 62 | }}} |
| | 63 | |
| | 64 | * {{{idx_orders_status_purchase_date}}} was successfully used as an Index Only Scan and reduced the cost of filtering orders by status and purchase date. |
| | 65 | |
| | 66 | * {{{idx_order_products_order_product_quantity}}} was not used by the optimizer, because a sequential scan of order_products was still considered cheaper for the current dataset. |