|
|
-- ============================================
|
|
|
-- 数据库索引优化建议
|
|
|
-- 基于 coursesHome 统计逻辑分析
|
|
|
-- ============================================
|
|
|
|
|
|
-- ============================================
|
|
|
-- 1. course_signs 表索引
|
|
|
-- ============================================
|
|
|
|
|
|
-- 1.1 核心查询索引:status + course_id(最常用)
|
|
|
-- 用于:courseSignsTotal, courseSignsTotalByUnique, getStudentList
|
|
|
-- 查询条件:status, course_id, whereHas('course')
|
|
|
ALTER TABLE `course_signs`
|
|
|
ADD INDEX `idx_status_course_id` (`status`, `course_id`);
|
|
|
|
|
|
-- 1.2 用户去重查询索引:user_id + status
|
|
|
-- 用于:courseSignsTotalByUnique(按手机号去重)
|
|
|
ALTER TABLE `course_signs`
|
|
|
ADD INDEX `idx_user_id_status` (`user_id`, `status`);
|
|
|
|
|
|
-- 1.3 排除状态索引:status(用于 whereNotIn status [4,5,6])
|
|
|
-- 注意:如果 status 字段选择性不高,可考虑与 course_id 组合
|
|
|
ALTER TABLE `course_signs`
|
|
|
ADD INDEX `idx_status_not_in` (`status`);
|
|
|
|
|
|
-- 1.4 复合索引:status + course_id + user_id(用于关联查询优化)
|
|
|
ALTER TABLE `course_signs`
|
|
|
ADD INDEX `idx_status_course_user` (`status`, `course_id`, `user_id`);
|
|
|
|
|
|
-- ============================================
|
|
|
-- 2. courses 表索引
|
|
|
-- ============================================
|
|
|
|
|
|
-- 2.1 图表统计索引:is_chart + 日期范围
|
|
|
-- 用于:getStudentList 中的 whereHas('course')
|
|
|
-- 查询条件:is_chart=1, start_date/end_date BETWEEN
|
|
|
ALTER TABLE `courses`
|
|
|
ADD INDEX `idx_is_chart_dates` (`is_chart`, `start_date`, `end_date`);
|
|
|
|
|
|
-- 2.2 课程体系索引:type + is_chart
|
|
|
-- 用于:按课程体系筛选课程
|
|
|
ALTER TABLE `courses`
|
|
|
ADD INDEX `idx_type_is_chart` (`type`, `is_chart`);
|
|
|
|
|
|
-- 2.3 复合索引:type + is_chart + start_date + end_date
|
|
|
-- 用于:课程分类明细统计
|
|
|
ALTER TABLE `courses`
|
|
|
ADD INDEX `idx_type_chart_dates` (`type`, `is_chart`, `start_date`, `end_date`);
|
|
|
|
|
|
-- ============================================
|
|
|
-- 3. calendars 表索引
|
|
|
-- ============================================
|
|
|
|
|
|
-- 3.1 日期范围查询索引:start_time + end_time
|
|
|
-- 用于:getCourseTotal, getCourseDayTotal
|
|
|
-- 查询条件:start_time/end_time BETWEEN
|
|
|
ALTER TABLE `calendars`
|
|
|
ADD INDEX `idx_dates_range` (`start_time`, `end_time`);
|
|
|
|
|
|
-- 3.2 课程体系索引:course_type_id + 日期
|
|
|
-- 用于:按课程体系筛选日历
|
|
|
ALTER TABLE `calendars`
|
|
|
ADD INDEX `idx_course_type_dates` (`course_type_id`, `start_time`, `end_time`);
|
|
|
|
|
|
-- 3.3 统计天数索引:is_count_days + 日期
|
|
|
-- 用于:getCourseDayTotal(开课天数统计)
|
|
|
ALTER TABLE `calendars`
|
|
|
ADD INDEX `idx_count_days_dates` (`is_count_days`, `start_time`, `end_time`);
|
|
|
|
|
|
-- 3.4 课程关联索引:course_id + course_type_id
|
|
|
-- 用于:通过 course.type 匹配课程体系
|
|
|
ALTER TABLE `calendars`
|
|
|
ADD INDEX `idx_course_type_id` (`course_id`, `course_type_id`);
|
|
|
|
|
|
-- ============================================
|
|
|
-- 4. companies 表索引
|
|
|
-- ============================================
|
|
|
|
|
|
-- 4.1 上市公司索引:company_market
|
|
|
-- 用于:shangshi, suzhouStock(上市公司统计)
|
|
|
ALTER TABLE `companies`
|
|
|
ADD INDEX `idx_company_market` (`company_market`);
|
|
|
|
|
|
-- 4.2 被投企业索引:is_yh_invested
|
|
|
-- 用于:yhInvestedTotal, companyInvestedYear(被投企业统计)
|
|
|
ALTER TABLE `companies`
|
|
|
ADD INDEX `idx_is_yh_invested` (`is_yh_invested`);
|
|
|
|
|
|
-- 4.3 企业标签索引:company_tag(用于 LIKE 查询)
|
|
|
-- 用于:toubuqiye(高新技术企业筛选)
|
|
|
-- 注意:LIKE '%高新技术企业%' 无法使用索引,但可以优化前缀匹配
|
|
|
ALTER TABLE `companies`
|
|
|
ADD INDEX `idx_company_tag` (`company_tag`(100));
|
|
|
|
|
|
-- 4.4 城市区域索引:company_city + company_area
|
|
|
-- 用于:area(区域统计), isSuzhou(苏州筛选)
|
|
|
ALTER TABLE `companies`
|
|
|
ADD INDEX `idx_city_area` (`company_city`, `company_area`);
|
|
|
|
|
|
-- 4.5 地址索引:company_address(用于 LIKE 查询)
|
|
|
-- 用于:isSuzhou(苏州筛选)
|
|
|
-- 注意:LIKE '%苏州%' 无法使用索引,但可以优化前缀匹配
|
|
|
ALTER TABLE `companies`
|
|
|
ADD INDEX `idx_company_address` (`company_address`(100));
|
|
|
|
|
|
-- 4.6 复合索引:company_market + company_city(用于苏州上市公司)
|
|
|
ALTER TABLE `companies`
|
|
|
ADD INDEX `idx_market_city` (`company_market`, `company_city`);
|
|
|
|
|
|
-- ============================================
|
|
|
-- 5. users 表索引
|
|
|
-- ============================================
|
|
|
|
|
|
-- 5.1 公司关联索引:company_id
|
|
|
-- 用于:通过用户关联公司
|
|
|
ALTER TABLE `users`
|
|
|
ADD INDEX `idx_company_id` (`company_id`);
|
|
|
|
|
|
-- 5.2 跟班学员索引:from(用于 LIKE 查询)
|
|
|
-- 用于:genban, ganbu(跟班学员统计)
|
|
|
-- 注意:LIKE '%跟班学员%' 无法使用索引,但可以优化前缀匹配
|
|
|
ALTER TABLE `users`
|
|
|
ADD INDEX `idx_from` (`from`(50));
|
|
|
|
|
|
-- 5.3 手机号索引:mobile(用于去重)
|
|
|
-- 用于:courseSignsTotalByUnique(按手机号去重)
|
|
|
ALTER TABLE `users`
|
|
|
ADD INDEX `idx_mobile` (`mobile`);
|
|
|
|
|
|
-- 5.4 公司名称索引:company_name(用于 LIKE 查询)
|
|
|
-- 用于:companyJoin(元和员工筛选)
|
|
|
-- 注意:LIKE '%元禾控股%' 等无法使用索引
|
|
|
ALTER TABLE `users`
|
|
|
ADD INDEX `idx_company_name` (`company_name`(100));
|
|
|
|
|
|
-- 5.5 用户地址索引:company_address(用于 LIKE 查询)
|
|
|
-- 用于:isSuzhou(苏州筛选)
|
|
|
ALTER TABLE `users`
|
|
|
ADD INDEX `idx_user_company_address` (`company_address`(100));
|
|
|
|
|
|
-- 5.6 复合索引:company_id + from(用于跟班学员筛选)
|
|
|
ALTER TABLE `users`
|
|
|
ADD INDEX `idx_company_from` (`company_id`, `from`(50));
|
|
|
|
|
|
-- ============================================
|
|
|
-- 6. stock_companies 表索引
|
|
|
-- ============================================
|
|
|
|
|
|
-- 6.1 上市日期索引:stock_date
|
|
|
-- 用于:company_market_year_total(今年上市公司数量)
|
|
|
ALTER TABLE `stock_companys`
|
|
|
ADD INDEX `idx_stock_date` (`stock_date`);
|
|
|
|
|
|
-- 6.2 入学后上市索引:is_after_enrollment
|
|
|
-- 用于:company_market_after_enrollment_total
|
|
|
ALTER TABLE `stock_companys`
|
|
|
ADD INDEX `idx_after_enrollment` (`is_after_enrollment`);
|
|
|
|
|
|
-- 6.3 公司关联索引:company_id
|
|
|
-- 用于:关联 companies 表
|
|
|
ALTER TABLE `stock_companys`
|
|
|
ADD INDEX `idx_company_id` (`company_id`);
|
|
|
|
|
|
-- 6.4 复合索引:is_after_enrollment + stock_date
|
|
|
ALTER TABLE `stock_companys`
|
|
|
ADD INDEX `idx_enrollment_date` (`is_after_enrollment`, `stock_date`);
|
|
|
|
|
|
-- ============================================
|
|
|
-- 7. history_courses 表索引
|
|
|
-- ============================================
|
|
|
|
|
|
-- 7.1 日期范围索引:start_time + end_time
|
|
|
-- 用于:历史课程统计
|
|
|
ALTER TABLE `history_courses`
|
|
|
ADD INDEX `idx_history_dates` (`start_time`, `end_time`);
|
|
|
|
|
|
-- 7.2 课程类型索引:type + 日期
|
|
|
-- 用于:按课程体系筛选历史课程
|
|
|
ALTER TABLE `history_courses`
|
|
|
ADD INDEX `idx_type_dates` (`type`, `start_time`, `end_time`);
|
|
|
|
|
|
-- 7.3 日历关联索引:calendar_id
|
|
|
-- 用于:whereHas('calendar', is_count_people=1)
|
|
|
ALTER TABLE `history_courses`
|
|
|
ADD INDEX `idx_calendar_id` (`calendar_id`);
|
|
|
|
|
|
-- 7.4 复合索引:type + calendar_id + 日期
|
|
|
ALTER TABLE `history_courses`
|
|
|
ADD INDEX `idx_type_calendar_dates` (`type`, `calendar_id`, `start_time`, `end_time`);
|
|
|
|
|
|
-- ============================================
|
|
|
-- 8. course_types 表索引
|
|
|
-- ============================================
|
|
|
|
|
|
-- 8.1 历史课程索引:is_history
|
|
|
-- 用于:筛选历史课程类型
|
|
|
ALTER TABLE `course_types`
|
|
|
ADD INDEX `idx_is_history` (`is_history`);
|
|
|
|
|
|
-- 8.2 跟班学员统计索引:is_count_genban
|
|
|
-- 用于:genban(筛选需要统计跟班学员的课程)
|
|
|
ALTER TABLE `course_types`
|
|
|
ADD INDEX `idx_is_count_genban` (`is_count_genban`);
|
|
|
|
|
|
-- ============================================
|
|
|
-- 9. 关联查询优化索引
|
|
|
-- ============================================
|
|
|
|
|
|
-- 9.1 course_signs 关联 users 优化
|
|
|
-- 已通过 user_id 索引优化
|
|
|
|
|
|
-- 9.2 users 关联 course_signs 优化
|
|
|
-- 需要在 course_signs 表已有 user_id 索引
|
|
|
|
|
|
-- 9.3 companies 关联 users 优化
|
|
|
-- 需要在 users 表已有 company_id 索引
|
|
|
|
|
|
-- 9.4 courses 关联 course_types 优化
|
|
|
-- 需要在 courses 表已有 type 索引
|
|
|
|
|
|
-- ============================================
|
|
|
-- 10. 特殊查询优化建议
|
|
|
-- ============================================
|
|
|
|
|
|
-- 10.1 JSON 字段查询优化
|
|
|
-- companies.project_users 字段(JSON)无法直接建立索引
|
|
|
-- 建议:如果 investDate 查询频繁,考虑单独建立 invest_dates 表或字段
|
|
|
|
|
|
-- 10.2 LIKE 查询优化
|
|
|
-- 对于 '%关键词%' 类型的 LIKE 查询,无法使用普通索引
|
|
|
-- 建议:
|
|
|
-- 1. 如果可能,改为前缀匹配 '关键词%' 可以使用索引
|
|
|
-- 2. 考虑使用全文索引(FULLTEXT):
|
|
|
ALTER TABLE `companies`
|
|
|
ADD FULLTEXT INDEX `ft_company_tag` (`company_tag`);
|
|
|
|
|
|
ALTER TABLE `users`
|
|
|
ADD FULLTEXT INDEX `ft_company_name` (`company_name`);
|
|
|
|
|
|
ALTER TABLE `users`
|
|
|
ADD FULLTEXT INDEX `ft_from` (`from`);
|
|
|
|
|
|
-- 10.3 日期范围查询优化
|
|
|
-- 对于 start_date/end_date BETWEEN 查询,确保日期字段有索引
|
|
|
-- 对于 orWhereBetween 查询,MySQL 可能无法同时使用两个索引
|
|
|
-- 建议:如果性能问题,考虑拆分为两个查询 UNION
|
|
|
|
|
|
-- ============================================
|
|
|
-- 11. 索引使用说明
|
|
|
-- ============================================
|
|
|
|
|
|
-- 11.1 索引创建顺序
|
|
|
-- 建议按照表的数据量和查询频率,优先创建高频查询的索引
|
|
|
|
|
|
-- 11.2 索引维护
|
|
|
-- 定期使用 EXPLAIN 分析查询计划,确认索引被正确使用
|
|
|
-- 示例:EXPLAIN SELECT * FROM course_signs WHERE status=1 AND course_id IN (1,2,3);
|
|
|
|
|
|
-- 11.3 索引监控
|
|
|
-- 使用以下查询监控索引使用情况:
|
|
|
-- SELECT * FROM sys.schema_unused_indexes;
|
|
|
-- SELECT * FROM performance_schema.table_io_waits_summary_by_index_usage;
|
|
|
|
|
|
-- 11.4 注意事项
|
|
|
-- 1. 索引会占用存储空间,增加写入成本
|
|
|
-- 2. 不要过度索引,每个表建议不超过 5-7 个索引
|
|
|
-- 3. 复合索引的顺序很重要,将选择性高的字段放在前面
|
|
|
-- 4. 定期分析表,更新统计信息:ANALYZE TABLE table_name;
|
|
|
|
|
|
-- ============================================
|
|
|
-- 12. 性能优化建议
|
|
|
-- ============================================
|
|
|
|
|
|
-- 12.1 查询优化
|
|
|
-- 1. 避免在 WHERE 子句中使用函数
|
|
|
-- 2. 使用 EXISTS 替代 IN(当子查询结果集较大时)
|
|
|
-- 3. 合理使用 JOIN,避免过度嵌套
|
|
|
|
|
|
-- 12.2 分页优化
|
|
|
-- 对于大数据量分页,考虑使用游标分页替代 OFFSET
|
|
|
|
|
|
-- 12.3 缓存策略
|
|
|
-- 对于统计类查询,考虑使用 Redis 缓存结果
|
|
|
|
|
|
-- ============================================
|
|
|
-- 索引创建脚本执行顺序建议
|
|
|
-- ============================================
|
|
|
|
|
|
-- 1. 先创建核心表索引(course_signs, courses, calendars)
|
|
|
-- 2. 再创建关联表索引(companies, users)
|
|
|
-- 3. 最后创建辅助表索引(stock_companies, history_courses)
|
|
|
|
|
|
-- 执行前请备份数据库!
|
|
|
-- 建议在业务低峰期执行索引创建操作
|
|
|
|