]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
feat(ERP-237): 6 индексов для устранения медленных запросов из pg_stat_statements origin/feature_filippov_ERP-237_missing_indexes
authorAleksey Filippov <Aleksey.Filippov@erp-flowers.ru>
Thu, 19 Mar 2026 13:31:35 +0000 (16:31 +0300)
committerAleksey Filippov <Aleksey.Filippov@erp-flowers.ru>
Thu, 19 Mar 2026 13:31:35 +0000 (16:31 +0300)
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

erp24/migrations/m260319_150000_add_missing_indexes_for_slow_queries.php [new file with mode: 0644]

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 (file)
index 0000000..fbef607
--- /dev/null
@@ -0,0 +1,108 @@
+<?php
+
+use yii\db\Migration;
+
+/**
+ * ERP-237: Добавление отсутствующих индексов для устранения узких мест из pg_stat_statements.
+ *
+ * Анализ показал ~2108s суммарного времени на запросы без индексов.
+ * Индекс api_cron.request_id уже создан в m260210_120000.
+ *
+ * Оставшиеся 6 индексов:
+ * - 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
+ */
+class m260319_150000_add_missing_indexes_for_slow_queries extends Migration
+{
+    public function safeUp(): void
+    {
+        // 1. export_import_table: 2.3M запросов, 511s
+        // WHERE entity=$1 AND export_id=$2 AND export_val=$3
+        if (!$this->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();
+    }
+}