问题
相同SQL程序查询1天内数据慢,手动查询1天内数据快。最近上线的某个偏AP类业务从MySQL迁移到TiDB,应用程序SQL无改动
版本
TiDB版本6.1.5
Mybatis prepare预编译形式发送的SQL
jdbc版本
jdbc:mysql://%s:%s/%s?characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&connectTimeout=2000&socketTimeout=600000
表结构索引
#SQL语句
select xxxx FROM
xxxxx_004 l
WHERE
l.mart_code = 'xxxx'
AND l.yn = 1
AND l.supplier_code = ?
AND l.biz_date >= ?
AND l.biz_date <= ?
ORDER BY
created DESC,
id DESC
LIMIT
40 [arguments: ("xxxx", "2024-01-18 00:00:00", "2024-01-18 00:00:00")];
#表结构
CREATE TABLE `xxxxxx_004` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`mart_code` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`ledger_no` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT xxxx,
`busi_no` varchar(650) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT xxxx,
`supplier_code` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT xxxx,
`supplier_name` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT xxxx,
`contract_no` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT xxxx,
`contract_type` tinyint(4) DEFAULT NULL COMMENT xxxx,
`direct_source_no` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT xxxx,
`exec_detail_uk` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT xxxx,
`schedule_no` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT xxxx,
`profit` tinyint(4) DEFAULT NULL COMMENT xxxx,
`discount_way` tinyint(4) DEFAULT NULL COMMENT xxxx,
`sku_id` bigint(20) DEFAULT NULL,
`goods_code` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT xxxx,
`goods_name` varchar(256) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT xxxx,
`shop_code` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT xxxx,
`shop_type` tinyint(4) DEFAULT NULL COMMENT xxxx,
`store_id` bigint(20) DEFAULT NULL COMMENT xxxx,
`shop_name` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT xxxx,
`rebate_type` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT xxxx,
`contract_state` tinyint(4) DEFAULT NULL COMMENT xxxx,
`create_type` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`quantity` decimal(20,5) DEFAULT NULL COMMENT xxxx,
`channel_type` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT xxxx,
`ledger_amount_taxed` decimal(20,5) DEFAULT NULL COMMENT xxxx,
`ledger_amount_untaxed` decimal(20,5) DEFAULT NULL COMMENT xxxx,
`ledger_amount_attached` decimal(20,5) DEFAULT NULL COMMENT xxxx,
`amount_taxed` decimal(20,5) DEFAULT NULL COMMENT xxxx,
`amount_untaxed` decimal(20,5) DEFAULT NULL COMMENT xxxx,
`goods_tax_code` varchar(16) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT xxxx,
`goods_tax_ratio` decimal(20,4) DEFAULT NULL COMMENT xxxx,
`tax_ratio` decimal(20,8) DEFAULT NULL COMMENT xxxx,
`collect_date` date DEFAULT NULL COMMENT xxxx,
`mode` tinyint(4) DEFAULT NULL COMMENT xxxx,
`bill_no` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT xxxx,
`order_no` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT xxxx,
`biz_start_date` date DEFAULT NULL,
`biz_end_date` date DEFAULT NULL COMMENT xxxx,
`biz_date` date DEFAULT NULL COMMENT xxxx,
`contract_day` date DEFAULT NULL COMMENT xxxx,
`category_mi` varchar(32) COLLATE DEFAULT '',
`category_sm` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT '',
`category` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT '',
`category_la` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT '',
`unit` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT xxxx,
`created_user` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`extend_filed` text COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT xxxx,
`remarks` varchar(128) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`created` datetime DEFAULT CURRENT_TIMESTAMP,
`modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`yn` tinyint(4) NOT NULL DEFAULT '1')
#表索引
PRIMARY (id)
uk_ledgerno (ledger_no,mart_code,yn)
idx_billno (bill_no)
idx_orderno (order_no)
idx_collectdate_billno_orderno (collect_date,bill_no,order_no,supplier_code,contract_no,rebate_type,contract_type,profit)
idx_directsourceno_rebatetype_busino (direct_source_no,rebate_type,busi_no,yn)
idx_suppliercode_busino (supplier_code,busi_no)
idx_suppliercode_contractno_bizdate (supplier_code,contract_no,biz_date)
idx_suppliercode_bizdate (supplier_code,biz_date)
idx_suppliercode_shopcode_bizdate (supplier_code,shop_code,biz_date)
idx_bizdate (biz_date)
idx_contractno (contract_no)
idx_busino (busi_no)
idx_suppliercode_bizstartdate (supplier_code,biz_start_date,biz_end_date)
idx_created_suppliercode_rebatetype (created,supplier_code,rebate_type)
idx_modified_created_mart (modified,created,mart_code)
表现
业务查询一天内数据页面超时
业务查询多天内数据页面反而快(走到了正确联合索引)
排查分析
TiDB dashboard中有几个3分多钟慢查询
表统计信息健康度为:99良好
TiDB集群自身无压力
页面程序查询一天内数据和人工手动执行走到不同索引(相同SQL)
程序执行(TiDB) | 人工手动执行(TiDB) | 人工手动执行(MySQL) |
---|---|---|
查询条件:WHERE l.mart_code = ‘xxxx’ AND l.yn = 1 AND l.supplier_code = ? AND l.biz_date >= ? AND l.biz_date <= ? ORDER BY created DESC, id DESC LIMIT 40 [arguments: (“xxxx”, “2024-01-18 00:00:00”, “2024-01-18 00:00:00”)]; | ||
走索引:idx_suppliercode_bizstartdate(supplier_code, biz_start_date, biz_end_date),相当于只走到了一个字段条件supplier_code索引过滤,另一个条件biz_date没走到索引过滤 → 耗时3.5分钟(不符合预期) | 走索引:index:idx_suppliercode_bizdate(supplier_code, biz_date) → 耗时183ms(符合预期) | 走索引:idx_suppliercode_bizdate(supplier_code, biz_date) → 耗时54ms(符合预期) |
截图信息:
程序执行(TiDB)
人工手动执行(TiDB)
人工手动执行(MySQL)
临时解决
-
程序临时增加新查询条件(SQL走到联合索引)
-
研发显示在代码SQL中增加强制索引force index(SQL类型多 改造难度大)
-
TiDB层面创建执行计划绑定(SQL行数多需要参数化不好创建)
如
CREATE BINDING FOR SELECT * FROM t WHERE a > 1 USING SELECT * FROM t use index(idx) WHERE b > 2;
已解决
- 关闭计算节点执行计划缓存后,业务应用研发去掉代码强制索引,页面报表查询1天内数据变快(走到了正确联合索引)
# 3个计算节点分别执行
ADMIN FLUSH INSTANCE PLAN_CACHE;
# 全局执行一次
set global tidb_enable_prepared_plan_cache=false;