package exporter import ( "database/sql" "fmt" "strings" "marketing-system-data-tool/server/internal/schema" ) func EvaluateExplain(db *sql.DB, q string, args []interface{}) (int, []string, error) { rows, score, err := RunExplain(db, q, args) if err != nil { return 0, nil, err } sugg := []string{} for _, r := range rows { // tbl := r.Table.String typ := r.Type.String if typ == "" && r.SelectType.Valid { typ = r.SelectType.String } if typ == "ALL" { sugg = append(sugg, "出现全表扫描(ALL),请在过滤或连接列上建立索引") } if r.Extra.Valid { e := r.Extra.String if contains(e, "Using temporary") || contains(e, "Using filesort") { sugg = append(sugg, "出现临时表或文件排序,请优化排序列及索引覆盖") } } } return score, sugg, nil } func IndexSuggestions(req BuildRequest) []string { sugg := []string{} sch := schema.Get(req.Datasource, req.MainTable) // Filter-based suggestions has := func(k string) bool { _, ok := req.Filters[k]; return ok } add := func(s string){ if s != "" { sugg = append(sugg, s) } } if has("creator_in") && has("create_time_between") { add(fmt.Sprintf("建议在 `%s`(create_time, %s) 建立复合索引以覆盖权限与时间范围", sch.TableName("order"), colName(sch, "creator_in"))) } else { if has("creator_in") { add(fmt.Sprintf("建议在 `%s`(%s) 建立索引以覆盖权限过滤", sch.TableName("order"), colName(sch, "creator_in"))) } if has("create_time_between") { add(fmt.Sprintf("建议在 `%s`(create_time) 建立索引以覆盖时间范围", sch.TableName("order"))) } } if has("plan_id_eq") { add(fmt.Sprintf("建议在 `%s`(%s) 建立索引以覆盖活动/计划过滤", sch.TableName("order"), colName(sch, "plan_id_eq"))) } if has("reseller_id_eq") { add(fmt.Sprintf("建议在 `%s`(%s) 建立索引以覆盖分销商过滤", sch.TableName("order"), colName(sch, "reseller_id_eq"))) } if has("product_id_eq") { add(fmt.Sprintf("建议在 `%s`(%s) 建立索引以覆盖商品过滤", sch.TableName("order"), colName(sch, "product_id_eq"))) } if has("out_trade_no_eq") { add(fmt.Sprintf("建议在 `%s`(%s) 建立索引以覆盖支付流水过滤", sch.TableName("order"), colName(sch, "out_trade_no_eq"))) } // Table usage-based join suggestions usedTables := map[string]bool{} for _, tf := range req.Fields { parts := strings.Split(tf, ".") if len(parts)==2 { usedTables[parts[0]] = true } } if req.MainTable == "order_info" { add("建议在 `order_info`(order_no) 建立索引以优化与子表的连接") if usedTables["order_cash"] { add("建议在 `order_cash`(order_no) 建立索引以优化与主表的连接") } if usedTables["order_voucher"] { add("建议在 `order_voucher`(order_no) 建立索引以优化与主表的连接") } if usedTables["order_digit"] { add("建议在 `order_digit`(order_no) 建立索引以优化与主表的连接") } if usedTables["goods_voucher_batch"] { add("建议在 `goods_voucher_batch`(channel_batch_no) 建立索引以优化与订单立减金的连接") } if usedTables["goods_voucher_subject_config"] { add("建议在 `goods_voucher_subject_config`(id) 上确保主键索引以优化连接") } if usedTables["merchant"] { add("建议在 `merchant`(id) 上确保主键索引以优化连接") } if usedTables["activity"] { add("建议在 `activity`(id) 上确保主键索引以优化连接") } } return dedup(sugg) } func colName(sch schema.Schema, key string) string { if _, col, ok := sch.FilterColumn(key); ok { return col } return "" } func dedup(arr []string) []string { m := map[string]bool{} out := []string{} for _, s := range arr { if !m[s] { m[s]=true; out = append(out, s) } } return out }