perf: V0.9.1-0.9.3 性能优化(count/featured 全表→聚合、请求内缓存、二级索引、PSI 未读铃铛)
- V0.9.1 (P0): Model::count() 改 SELECT COUNT(*);新增请求内 identity-map 缓存; Product::featured() 改 WHERE+ LIMIT 避免全表 - V0.9.2 (P1): schema.sql 内联二级索引 + install/upgrades/009_perf_indexes.sql 幂等迁移 - V0.9.3 (P1): psi_unread_events() 改 COUNT + JSON_CONTAINS,消除每页 all()+循环
This commit is contained in:
+52
-20
@@ -10,7 +10,8 @@ CREATE TABLE IF NOT EXISTS `categories` (
|
||||
`sort_order` INT DEFAULT 0,
|
||||
`status` TINYINT DEFAULT 1,
|
||||
`layout` TEXT,
|
||||
`mode` VARCHAR(16) NOT NULL DEFAULT 'fixed'
|
||||
`mode` VARCHAR(16) NOT NULL DEFAULT 'fixed',
|
||||
KEY idx_categories_slug (slug)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `products` (
|
||||
@@ -29,7 +30,10 @@ CREATE TABLE IF NOT EXISTS `products` (
|
||||
`status` TINYINT DEFAULT 1,
|
||||
`created_at` VARCHAR(20) DEFAULT '',
|
||||
`layout` TEXT,
|
||||
`mode` VARCHAR(16) NOT NULL DEFAULT 'fixed'
|
||||
`mode` VARCHAR(16) NOT NULL DEFAULT 'fixed',
|
||||
KEY idx_products_category_id (category_id),
|
||||
KEY idx_products_slug (slug),
|
||||
KEY idx_products_status (status)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `news` (
|
||||
@@ -44,7 +48,9 @@ CREATE TABLE IF NOT EXISTS `news` (
|
||||
`status` TINYINT DEFAULT 1,
|
||||
`views` INT DEFAULT 0,
|
||||
`layout` TEXT,
|
||||
`mode` VARCHAR(16) NOT NULL DEFAULT 'fixed'
|
||||
`mode` VARCHAR(16) NOT NULL DEFAULT 'fixed',
|
||||
KEY idx_news_slug (slug),
|
||||
KEY idx_news_status (status)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `cases` (
|
||||
@@ -61,7 +67,9 @@ CREATE TABLE IF NOT EXISTS `cases` (
|
||||
`status` TINYINT DEFAULT 1,
|
||||
`views` INT DEFAULT 0,
|
||||
`layout` TEXT,
|
||||
`mode` VARCHAR(16) NOT NULL DEFAULT 'fixed'
|
||||
`mode` VARCHAR(16) NOT NULL DEFAULT 'fixed',
|
||||
KEY idx_cases_slug (slug),
|
||||
KEY idx_cases_status (status)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `pages` (
|
||||
@@ -71,7 +79,8 @@ CREATE TABLE IF NOT EXISTS `pages` (
|
||||
`content` TEXT,
|
||||
`layout` TEXT,
|
||||
`mode` VARCHAR(16) NOT NULL DEFAULT 'fixed',
|
||||
`updated_at` VARCHAR(20) DEFAULT ''
|
||||
`updated_at` VARCHAR(20) DEFAULT '',
|
||||
KEY idx_pages_slug (slug)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `banners` (
|
||||
@@ -81,7 +90,9 @@ CREATE TABLE IF NOT EXISTS `banners` (
|
||||
`image` VARCHAR(255) DEFAULT '',
|
||||
`link` VARCHAR(255) DEFAULT '',
|
||||
`sort_order` INT DEFAULT 0,
|
||||
`status` TINYINT DEFAULT 1
|
||||
`status` TINYINT DEFAULT 1,
|
||||
KEY idx_banners_status (status),
|
||||
KEY idx_banners_sort (sort_order)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `admin_users` (
|
||||
@@ -95,7 +106,8 @@ CREATE TABLE IF NOT EXISTS `admin_users` (
|
||||
`crm_perms` TEXT,
|
||||
`psi_perms` TEXT,
|
||||
`status` TINYINT DEFAULT 1,
|
||||
`created_at` VARCHAR(20) DEFAULT ''
|
||||
`created_at` VARCHAR(20) DEFAULT '',
|
||||
KEY idx_admin_users_role (role)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
/* ===================== CRM 客户管理系统 ===================== */
|
||||
@@ -117,7 +129,8 @@ CREATE TABLE IF NOT EXISTS `crm_customers` (
|
||||
`status` VARCHAR(20) DEFAULT 'lead',
|
||||
`remark` TEXT,
|
||||
`owner` VARCHAR(60) DEFAULT '',
|
||||
`created_at` VARCHAR(20) DEFAULT ''
|
||||
`created_at` VARCHAR(20) DEFAULT '',
|
||||
KEY idx_customers_status (status)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `crm_contacts` (
|
||||
@@ -130,7 +143,8 @@ CREATE TABLE IF NOT EXISTS `crm_contacts` (
|
||||
`wechat` VARCHAR(60) DEFAULT '',
|
||||
`is_primary` TINYINT DEFAULT 0,
|
||||
`remark` TEXT,
|
||||
`created_at` VARCHAR(20) DEFAULT ''
|
||||
`created_at` VARCHAR(20) DEFAULT '',
|
||||
KEY idx_contacts_customer_id (customer_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `crm_leads` (
|
||||
@@ -144,7 +158,8 @@ CREATE TABLE IF NOT EXISTS `crm_leads` (
|
||||
`probability` TINYINT DEFAULT 0,
|
||||
`owner` VARCHAR(60) DEFAULT '',
|
||||
`remark` TEXT,
|
||||
`created_at` VARCHAR(20) DEFAULT ''
|
||||
`created_at` VARCHAR(20) DEFAULT '',
|
||||
KEY idx_leads_customer_id (customer_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `crm_followups` (
|
||||
@@ -156,7 +171,9 @@ CREATE TABLE IF NOT EXISTS `crm_followups` (
|
||||
`way` VARCHAR(20) DEFAULT '',
|
||||
`result` VARCHAR(60) DEFAULT '',
|
||||
`owner` VARCHAR(60) DEFAULT '',
|
||||
`created_at` VARCHAR(20) DEFAULT ''
|
||||
`created_at` VARCHAR(20) DEFAULT '',
|
||||
KEY idx_followups_customer_id (customer_id),
|
||||
KEY idx_followups_lead_id (lead_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
/* ===================== 进销存 PSI 系统 ===================== */
|
||||
@@ -176,7 +193,9 @@ CREATE TABLE IF NOT EXISTS `psi_materials` (
|
||||
`price` DECIMAL(10,2) DEFAULT 0,
|
||||
`supplier_id` INT DEFAULT 0,
|
||||
`remark` TEXT,
|
||||
`created_at` VARCHAR(20) DEFAULT ''
|
||||
`created_at` VARCHAR(20) DEFAULT '',
|
||||
KEY idx_materials_supplier_id (supplier_id),
|
||||
KEY idx_materials_code (code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `psi_products` (
|
||||
@@ -195,7 +214,8 @@ CREATE TABLE IF NOT EXISTS `psi_products` (
|
||||
`cost` DECIMAL(10,2) DEFAULT 0,
|
||||
`price` DECIMAL(10,2) DEFAULT 0,
|
||||
`remark` TEXT,
|
||||
`created_at` VARCHAR(20) DEFAULT ''
|
||||
`created_at` VARCHAR(20) DEFAULT '',
|
||||
KEY idx_psi_products_code (code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `psi_suppliers` (
|
||||
@@ -225,7 +245,9 @@ CREATE TABLE IF NOT EXISTS `psi_purchases` (
|
||||
`batch_no` VARCHAR(40) DEFAULT '',
|
||||
`expected_at` VARCHAR(20) DEFAULT '',
|
||||
`remark` TEXT,
|
||||
`created_at` VARCHAR(20) DEFAULT ''
|
||||
`created_at` VARCHAR(20) DEFAULT '',
|
||||
KEY idx_purchases_supplier_id (supplier_id),
|
||||
KEY idx_purchases_order_no (order_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `psi_sales` (
|
||||
@@ -241,7 +263,8 @@ CREATE TABLE IF NOT EXISTS `psi_sales` (
|
||||
`region` VARCHAR(40) DEFAULT '',
|
||||
`batch_no` VARCHAR(40) DEFAULT '',
|
||||
`remark` TEXT,
|
||||
`created_at` VARCHAR(20) DEFAULT ''
|
||||
`created_at` VARCHAR(20) DEFAULT '',
|
||||
KEY idx_sales_order_no (order_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `psi_stock_moves` (
|
||||
@@ -253,14 +276,16 @@ CREATE TABLE IF NOT EXISTS `psi_stock_moves` (
|
||||
`ref_no` VARCHAR(40) DEFAULT '',
|
||||
`batch_no` VARCHAR(40) DEFAULT '',
|
||||
`remark` TEXT,
|
||||
`created_at` VARCHAR(20) DEFAULT ''
|
||||
`created_at` VARCHAR(20) DEFAULT '',
|
||||
KEY idx_stock_moves_item (item_type, item_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `settings` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`skey` VARCHAR(120) NOT NULL,
|
||||
`sval` TEXT,
|
||||
`sgroup` VARCHAR(40) DEFAULT 'site'
|
||||
`sgroup` VARCHAR(40) DEFAULT 'site',
|
||||
KEY idx_settings_sgroup (sgroup)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `orders` (
|
||||
@@ -277,7 +302,10 @@ CREATE TABLE IF NOT EXISTS `orders` (
|
||||
`status` VARCHAR(20) DEFAULT 'pending',
|
||||
`gateway_trade_no` VARCHAR(120) DEFAULT '',
|
||||
`paid_at` VARCHAR(20) DEFAULT '',
|
||||
`created_at` VARCHAR(20) DEFAULT ''
|
||||
`created_at` VARCHAR(20) DEFAULT '',
|
||||
KEY idx_orders_order_no (order_no),
|
||||
KEY idx_orders_status (status),
|
||||
KEY idx_orders_product_id (product_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `payments` (
|
||||
@@ -289,7 +317,9 @@ CREATE TABLE IF NOT EXISTS `payments` (
|
||||
`trade_no` VARCHAR(120) DEFAULT '',
|
||||
`status` VARCHAR(20) DEFAULT '',
|
||||
`created_at` VARCHAR(20) DEFAULT '',
|
||||
`paid_at` VARCHAR(20) DEFAULT ''
|
||||
`paid_at` VARCHAR(20) DEFAULT '',
|
||||
KEY idx_payments_order_id (order_id),
|
||||
KEY idx_payments_order_no (order_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `psi_events` (
|
||||
@@ -304,5 +334,7 @@ CREATE TABLE IF NOT EXISTS `psi_events` (
|
||||
`recipients` TEXT,
|
||||
`channels` VARCHAR(255) NOT NULL DEFAULT '["inapp"]',
|
||||
`read_by` TEXT,
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
KEY idx_events_sys (sys),
|
||||
KEY idx_events_level (level)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
-- V0.9.2 性能优化:为高频查询列补齐二级索引(MySQL 5.7 兼容)
|
||||
-- 通过存储过程判断索引是否已存在,重复执行不会报错。
|
||||
-- 部署方式:放入 install/upgrades/ 后,后台「数据库升级」一键应用(仅超级管理员)。
|
||||
-- 升级记录会写入 db_upgrades,内容不变不会重复执行。
|
||||
|
||||
DROP PROCEDURE IF EXISTS _perf_add_idx;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE _perf_add_idx(IN p_table VARCHAR(64), IN p_name VARCHAR(64), IN p_cols VARCHAR(255))
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = p_table AND INDEX_NAME = p_name
|
||||
) THEN
|
||||
SET @_perf_sql = CONCAT('ALTER TABLE `', p_table, '` ADD INDEX `', p_name, '` (', p_cols, ')');
|
||||
PREPARE _perf_stmt FROM @_perf_sql;
|
||||
EXECUTE _perf_stmt;
|
||||
DEALLOCATE PREPARE _perf_stmt;
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
CALL _perf_add_idx('categories','idx_categories_slug','`slug`');
|
||||
CALL _perf_add_idx('products','idx_products_category_id','`category_id`');
|
||||
CALL _perf_add_idx('products','idx_products_slug','`slug`');
|
||||
CALL _perf_add_idx('products','idx_products_status','`status`');
|
||||
CALL _perf_add_idx('news','idx_news_slug','`slug`');
|
||||
CALL _perf_add_idx('news','idx_news_status','`status`');
|
||||
CALL _perf_add_idx('cases','idx_cases_slug','`slug`');
|
||||
CALL _perf_add_idx('cases','idx_cases_status','`status`');
|
||||
CALL _perf_add_idx('pages','idx_pages_slug','`slug`');
|
||||
CALL _perf_add_idx('banners','idx_banners_status','`status`');
|
||||
CALL _perf_add_idx('banners','idx_banners_sort','`sort_order`');
|
||||
CALL _perf_add_idx('admin_users','idx_admin_users_role','`role`');
|
||||
CALL _perf_add_idx('orders','idx_orders_order_no','`order_no`');
|
||||
CALL _perf_add_idx('orders','idx_orders_status','`status`');
|
||||
CALL _perf_add_idx('orders','idx_orders_product_id','`product_id`');
|
||||
CALL _perf_add_idx('payments','idx_payments_order_id','`order_id`');
|
||||
CALL _perf_add_idx('payments','idx_payments_order_no','`order_no`');
|
||||
CALL _perf_add_idx('crm_customers','idx_customers_status','`status`');
|
||||
CALL _perf_add_idx('crm_contacts','idx_contacts_customer_id','`customer_id`');
|
||||
CALL _perf_add_idx('crm_leads','idx_leads_customer_id','`customer_id`');
|
||||
CALL _perf_add_idx('crm_followups','idx_followups_customer_id','`customer_id`');
|
||||
CALL _perf_add_idx('crm_followups','idx_followups_lead_id','`lead_id`');
|
||||
CALL _perf_add_idx('psi_materials','idx_materials_supplier_id','`supplier_id`');
|
||||
CALL _perf_add_idx('psi_materials','idx_materials_code','`code`');
|
||||
CALL _perf_add_idx('psi_products','idx_psi_products_code','`code`');
|
||||
CALL _perf_add_idx('psi_purchases','idx_purchases_supplier_id','`supplier_id`');
|
||||
CALL _perf_add_idx('psi_purchases','idx_purchases_order_no','`order_no`');
|
||||
CALL _perf_add_idx('psi_sales','idx_sales_order_no','`order_no`');
|
||||
CALL _perf_add_idx('psi_stock_moves','idx_stock_moves_item','`item_type`,`item_id`');
|
||||
CALL _perf_add_idx('settings','idx_settings_sgroup','`sgroup`');
|
||||
CALL _perf_add_idx('psi_events','idx_events_sys','`sys`');
|
||||
CALL _perf_add_idx('psi_events','idx_events_level','`level`');
|
||||
|
||||
DROP PROCEDURE IF EXISTS _perf_add_idx;
|
||||
Reference in New Issue
Block a user