tidb执行sql特别慢

  • 【TiDB 版本】:v4.0.1GA
  • 【问题描述】:
    同一条sql,运行在mysql和tidb中执行计划是不一样的。并且执行时间也不同。tidb没有mysql执行效率高
    上游mysql分表,查询其中一张表数据量是50w左右。查询时间为0.6s
    下游tidb是总表,查询数量为100w左右。查询时间为2.9s

【mysql执行计划】:


【tidb执行计划】:

【SQL语句】:
SELECT
a.member_id,
a.member_name,
a.PASSWORD,
a.pay_password,
a.salt,
a.sex,
a.avatar,
a.real_name,
a.id_card,
a.phone,
a.birthday,
a.nickname,
a.vip_level,
a.agency_member_id,
a.agency_member_name,
a.promotion_code,
a.register_resource,
a.register_ip,
a.register_address,
a.register_device,
a.member_type,
a.freeze_status,
a.wx_openid,
a.qq,
a.qq_openid,
a.remark,
a.online_status,
a.latest_login_ip,
a.latest_login_address,
a.latest_login_time,
a.latest_recharge_time,
a.latest_login_device,
a.tenant_code,
a.create_time,
a.update_time
FROM
app_member AS a
WHERE
1 = 1
AND a.tenant_code = ‘xgcp’
AND a.vip_level = 2
ORDER BY create_time DESC
LIMIT 20;

mysql> SHOW STATS_HEALTHY where table_name=‘app_member’;
±--------±-----------±---------------±--------+
| Db_name | Table_name | Partition_name | Healthy |
±--------±-----------±---------------±--------+
| cpt | app_member | | 100 |
±--------±-----------±---------------±--------+

【索引信息】:
mysql执行计划所用的组合索引-

Columns tenant_code
create_time
tidb执行计划所用到的组合索引
Columns tenant_code
member_type
【答疑】:
1.执行计划为什么不同,同时执行效率差这么多
2.tidb为什么在扫描到索引的情况下,比mysql多一次全表扫描

请上传表结构信息

CREATE TABLE app_member (
member_id bigint(20) NOT NULL,
member_name varchar(50) NOT NULL COMMENT ‘账号’,
password varchar(200) DEFAULT NULL COMMENT ‘密码’,
pay_password varchar(200) DEFAULT NULL COMMENT ‘支付密码’,
salt varchar(150) DEFAULT NULL COMMENT ‘盐’,
sex int(11) DEFAULT NULL COMMENT ‘性别:0-女;1-男’,
avatar varchar(255) DEFAULT NULL COMMENT ‘会员头像’,
real_name varchar(100) DEFAULT NULL COMMENT ‘真名’,
id_card varchar(19) DEFAULT NULL COMMENT ‘身份证号’,
phone varchar(15) DEFAULT NULL COMMENT ‘手机号’,
birthday date DEFAULT NULL COMMENT ‘生日’,
nickname varchar(100) DEFAULT NULL COMMENT ‘昵称’,
vip_level int(11) NOT NULL COMMENT ‘VIP等级’,
agency_member_id bigint(20) DEFAULT NULL COMMENT ‘代理ID’,
agency_member_name varchar(50) DEFAULT NULL COMMENT ‘所属代理的账号’,
promotion_code varchar(20) DEFAULT NULL COMMENT ‘推广码’,
register_resource varchar(10) NOT NULL COMMENT ‘注册来源:ios,android,h5,web’,
register_ip varchar(15) NOT NULL COMMENT ‘注册ip’,
register_address varchar(100) DEFAULT NULL COMMENT ‘注册地址’,
register_device varchar(50) DEFAULT NULL COMMENT ‘注册设备’,
install_from varchar(100) DEFAULT NULL COMMENT ‘APP来源地址’,
member_type int(11) DEFAULT NULL COMMENT ‘1-注册游客、2-注册用户、3-充值用户、4-测试用户’,
freeze_status int(11) DEFAULT NULL COMMENT ‘0-不冻结1-冻结’,
wx_openid varchar(255) DEFAULT NULL COMMENT ‘微信OPENID’,
qq varchar(20) DEFAULT NULL COMMENT ‘qq号码’,
qq_openid varchar(255) DEFAULT NULL COMMENT ‘qq_openid’,
remark varchar(255) DEFAULT NULL COMMENT ‘备注’,
online_status int(11) DEFAULT NULL COMMENT ‘0-在线,1-离线’,
latest_login_ip varchar(18) DEFAULT NULL COMMENT ‘最近一次登录IP’,
latest_login_address varchar(100) DEFAULT NULL COMMENT ‘最近一次登录地址’,
latest_login_time datetime DEFAULT NULL COMMENT ‘最近一次登录时间’,
latest_recharge_time datetime DEFAULT NULL COMMENT ‘最近一次充值时间’,
latest_login_device varchar(50) DEFAULT NULL COMMENT ‘最近一次登录设备’,
tenant_code varchar(32) NOT NULL COMMENT ‘租户编码’,
create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ‘创建时间’,
update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ‘最后修改时间’,
sum_recharge decimal(14,3) DEFAULT NULL COMMENT ‘’‘冗余字段充值金额’’’,
balance decimal(14,3) DEFAULT NULL COMMENT ‘’‘冗余字段余额’’’,
PRIMARY KEY (member_id),
UNIQUE KEY member_name (member_name,tenant_code),
KEY idx_tcode_ctime (tenant_code,create_time),
KEY idx_tcode_mtype (tenant_code,member_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT=‘会员表’;

1.tidb 优化器实现和支持的算子跟 mysql 不同,但都会根据当前的统计信息来选择最优的执行计划,从执行计划看 mysql 走了 idx_tcode_ctime 索引,tidb 走了idx_tcode_mtype 索引。由于上下游数据量差了一倍,tidb 需要扫描更多数据,执行效率会存在差异,此外 tidb 各组件之间的网络调用也存在一定开销。

2.tidb 这里的 TableRowIDScan 并不是全表扫描的意思,而是通过 idx_tcode_mtype 索引过滤后再回表查询数据的操作,mysql 也是需要回表的,只是执行计划中没有反映出这个步骤。

可以在 tenant_code,vip_level 建组合索引或者在 create_time 字段上建索引,分别用 use index 指定走这些索引并对比执行效率

即使数据差了一半,效率相差了几倍。这样看反而没有mysql性能高
网络是万兆,并且当前sql的查询条件vip_level只是其中之一。还有十几个查询条件是不是都要单独创建索引。这样单表就要十几个索引了
而且tidb和mysql走同样的索引(idx_tcode_ctime),性能如下:
mysql执行效率如下:



tidb执行效率如下:
时间: 3.891s

如果说是因为tidb仅比mysql多一半的数据量,走相同索引执行效率却相差7,8倍
那tidb的性能优势在什么地方

可以先尝试 tenant_code,vip_level 建组合索引或者在 create_time 字段上建索引,看看能否满足性能预期,优化器方面也在持续改进,如果有相关建议,也欢迎在论坛或 github 上留言。

对于数据量更大的场景,mysql 作为单机数据库,由于单机性能存在上限,会遇到瓶颈,tidb 通过水平扩展,可以扩容更多的计算和存储节点。