tidb没有用到索引

【TiDB 使用环境】生产环境
【TiDB 版本】
【操作系统】rocky 9
【部署方式】云上部署
【遇到的问题:问题现象及影响】
图片中的查询shop_id,end_time字段都有索引 为什么在最后一步中用的是TableFullScan?



表结构:

CREATE TABLE `m_platform_refund_info` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  `unique_key` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '唯一键',
  `refund_id` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '平台退款编号',
  `refund_type` tinyint NOT NULL DEFAULT '0' COMMENT '退款类型 1、发货前仅退款;2、发货后仅退款;3、退货退款',
  `refund_status` tinyint NOT NULL DEFAULT '0' COMMENT '退款状态。1.未退款,2.已退款,3.已取消',
  `apply_refund_fee` decimal(20,8) NOT NULL DEFAULT '0' COMMENT '申请退款金额(元)',
  `actually_refund_fee` decimal(20,8) NOT NULL DEFAULT '0' COMMENT '实退金额(元)',
  `refund_timeout` datetime DEFAULT NULL COMMENT '退款超时时间',
  `tid` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '平台订单号',
  `oid` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '平台子订单号',
  `oid_status` tinyint NOT NULL DEFAULT '0' COMMENT '对应的子订单的状态,1.待发货,2.部份分货,3.已发货,4.已完结,5.已关闭',
  `sku_sn` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'sku编码',
  `barcode` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '条码',
  `sku_id` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '订单商品表里的sku_id,京东必填',
  `order_sn` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'OMS里的order_sn',
  `user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'OMS用户id',
  `user_name` varchar(1024) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '买家名称',
  `buyer_open_uid` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'open_uid',
  `refund_reason` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '退款原因,一级',
  `refund_reason2` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '退款原因,二级',
  `return_status` tinyint NOT NULL DEFAULT '0' COMMENT '退货状态,1.无需退货 2.待退货 3.已退货 ',
  `return_num` int unsigned NOT NULL DEFAULT '0' COMMENT '退货数量',
  `ticket_sn` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '退货入库单号',
  `order_created` datetime DEFAULT NULL COMMENT '订单的创建时间',
  `order_pay_time` datetime DEFAULT NULL COMMENT '订单的支付时间',
  `created` datetime DEFAULT NULL COMMENT '申请退款时间(平台时间)',
  `modified` datetime DEFAULT NULL COMMENT '平台更新时间(平台)',
  `end_time` datetime DEFAULT NULL COMMENT '退款完成时间',
  `source` tinyint NOT NULL DEFAULT '1' COMMENT '退款来源 1.平台  2.手工',
  `shop_id` int unsigned NOT NULL DEFAULT '0' COMMENT 'sso的店铺id',
  `brand_id` int unsigned NOT NULL DEFAULT '0' COMMENT '品牌编码',
  `data_from` tinyint DEFAULT '0' COMMENT '数据来源,96.OMS,98.SAAS OMS,,1天猫,2.京东,13.抖音,5.唯品会,',
  `volume` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '数据源标识',
  `add_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '记录添加时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '记录更新时间',
  PRIMARY KEY (`id`) /*T![clustered_index] CLUSTERED */,
  KEY `tid` (`tid`),
  KEY `oid` (`oid`),
  KEY `sku_id` (`sku_id`),
  KEY `sku_sn` (`sku_sn`),
  KEY `end_time` (`end_time`),
  KEY `created` (`created`),
  KEY `refund_status` (`refund_status`),
  KEY `shop_id` (`shop_id`),
  UNIQUE KEY `unique_key` (`unique_key`),
  KEY `idx_update_time` (`update_time`),
  KEY `refund_id` (`refund_id`),
  KEY `idx_order_pay_time` (`order_pay_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci AUTO_INCREMENT=238943224 COMMENT='aaa'

请贴出索引信息

endtime,shop_id创建联合索引

KEY end_time (end_time ),改为联合索引

tidb适合用联合索引,不同于mysql,再就是手工analye表看看

:thinking: group by 里加上refund.brand_id ,然后再试试。

:thinking:应该是类型转换导致的。改成refund.shop_id = 498 ,然后再试试

2 个赞

非常有可能

不是这个问题,试过了

查询出来多少数据量,数据量大,优化器任务全表扫,性能好些

全表扫描4000多万,结果集也是4000多万。走索引跟不走索引耗时差不多吧

强制走索引看下评估成本就好了,看情况应该是单列索引选择度不够高

看一下你的表数据总量,以及满足这个条件的数据总量,如果相差很小,即绝大部分数据都包含在这个条件内,那么是不会走索引的。

说明你两个索引效果都不好,你hint指定分别走两个索引再贴一下执行计划,建议是建一个联合索引,或者直接上tiflash

表结构索引都是单列的,建议直接加一个shop_id,end_time的联合索引。索引都没选可能是因为过滤的数据还需要回表进行筛选,优化器计算的cost不如直接走tablefullscan来的cost合适。

但走那一个条件查询看看执行计划呢,你最后的结果集数量和全表都一样,这有点不对了吧

analye table 看看,在创联合索引呢

shop_id 和 end_time 刷选出来的符合条件的行数有多少,,具体得看选择率,如果符合条件得行很少,试试联合索引有没有效果,等值查询的列放在联合索引中的前面。

1 个赞

这两个条件 section 算子过滤后的数据是 56831,这个选择性还行。

创建 shop_id, end_time 组合索引。然后确保 shop_id 传的是数字类型。

先创建联合索引试试:

ALTER TABLE m_platform_refund_info ADD INDEX idx_shop_end_status (
    shop_id, 
    end_time, 
    refund_status,
    refund_type,
    actually_refund_fee
);

再改优化一下查询语句,类似于:

-- 先用索引过滤出符合条件的数据
WITH filtered_data AS (
    SELECT *
    FROM m_platform_refund_info
    WHERE shop_id = '498'
    AND end_time BETWEEN '2025-03-01 00:00:00' AND '2025-03-24 23:59:59'
)
-- 再进行聚合计算
SELECT 
    count(1) AS refund_num,
    sum(apply_refund_fee) AS refund_money,
    -- 其他聚合计算
    ...
FROM filtered_data;