From: Aleksey Filippov Date: Thu, 19 Mar 2026 13:31:35 +0000 (+0300) Subject: feat(ERP-237): 6 индексов для устранения медленных запросов из pg_stat_statements X-Git-Url: https://gitweb.erp-flowers.ru/?a=commitdiff_plain;h=4bd9156640553616ff73b0bcb881a24ea0a23e85;p=erp24_rep%2Fyii-erp24%2F.git feat(ERP-237): 6 индексов для устранения медленных запросов из pg_stat_statements export_import_table(entity, export_id, export_val) — 2.3M запросов, 511s marketplace_orders(guid) — 247K запросов, 412s marketplace_flowwow_emails(subject, from, date) — 253K запросов, 409s marketplace_order_items(order_id) — 376K запросов, 307s timetable_fact(admin_id, date, is_opening) — 52K запросов, 298s admin_payroll_days(admin_id, date) — 27K запросов, 278s --- diff --git a/erp24/migrations/m260319_150000_add_missing_indexes_for_slow_queries.php b/erp24/migrations/m260319_150000_add_missing_indexes_for_slow_queries.php new file mode 100644 index 00000000..fbef6079 --- /dev/null +++ b/erp24/migrations/m260319_150000_add_missing_indexes_for_slow_queries.php @@ -0,0 +1,108 @@ +indexExists('export_import_table', 'idx_export_import_table_entity_export_id_val')) { + $this->createIndex( + 'idx_export_import_table_entity_export_id_val', + 'export_import_table', + ['entity', 'export_id', 'export_val'] + ); + } + + // 2. marketplace_orders (guid): 247K запросов, 412s + // WHERE guid=$1 + if (!$this->indexExists('marketplace_orders', 'idx_marketplace_orders_guid')) { + $this->createIndex( + 'idx_marketplace_orders_guid', + 'marketplace_orders', + 'guid' + ); + } + + // 3. marketplace_flowwow_emails (subject, from, date): 253K, 409s + // SELECT EXISTS WHERE subject=$1 AND from=$2 AND date=$3 + if (!$this->indexExists('marketplace_flowwow_emails', 'idx_marketplace_flowwow_emails_subject_from_date')) { + $this->createIndex( + 'idx_marketplace_flowwow_emails_subject_from_date', + 'marketplace_flowwow_emails', + ['subject', '"from"', 'date'] + ); + } + + // 4. marketplace_order_items (order_id): 376K запросов, 307s + // SELECT * WHERE order_id=$1 + if (!$this->indexExists('marketplace_order_items', 'idx_marketplace_order_items_order_id')) { + $this->createIndex( + 'idx_marketplace_order_items_order_id', + 'marketplace_order_items', + 'order_id' + ); + } + + // 5. timetable_fact (admin_id, date, is_opening): 52K запросов, 298s + // WHERE admin_id=$1 AND (date=$2 OR date=$3) AND is_opening=$4 + if (!$this->indexExists('timetable_fact', 'idx_timetable_fact_admin_date_opening')) { + $this->createIndex( + 'idx_timetable_fact_admin_date_opening', + 'timetable_fact', + ['admin_id', 'date', 'is_opening'] + ); + } + + // 6. admin_payroll_days (admin_id, date): 27K запросов, 278s + if (!$this->indexExists('admin_payroll_days', 'idx_admin_payroll_days_admin_id')) { + $this->createIndex( + 'idx_admin_payroll_days_admin_id', + 'admin_payroll_days', + ['admin_id', 'date'] + ); + } + } + + public function safeDown(): void + { + $indexes = [ + ['idx_export_import_table_entity_export_id_val', 'export_import_table'], + ['idx_marketplace_orders_guid', 'marketplace_orders'], + ['idx_marketplace_flowwow_emails_subject_from_date', 'marketplace_flowwow_emails'], + ['idx_marketplace_order_items_order_id', 'marketplace_order_items'], + ['idx_timetable_fact_admin_date_opening', 'timetable_fact'], + ['idx_admin_payroll_days_admin_id', 'admin_payroll_days'], + ]; + + foreach ($indexes as [$indexName, $table]) { + if ($this->indexExists($table, $indexName)) { + $this->dropIndex($indexName, $table); + } + } + } + + private function indexExists(string $table, string $indexName): bool + { + return (bool) $this->db->createCommand( + "SELECT 1 FROM pg_indexes WHERE tablename = :table AND indexname = :index LIMIT 1", + [':table' => $table, ':index' => $indexName] + )->queryScalar(); + } +}