tidb-server 执行了一个占用内存大的sql语句,结束后内存不下来

为提高效率,提问时请提供以下信息,问题描述清晰可优先响应。

  • 【TiDB 版本】:V3.0.8
  • 【问题描述】:执行了一个大表与大表的join的复杂查询,查询完后内存没有释放
  1. 请执行top,free -h返回结果信息
  2. 上传tidb.log日志,包含执行sql的时间即可
  3. curl -G “ip:port/debug/pprof/heap?seconds=30” > heap.profile 收集火焰图
  4. 反馈explain sql信息
  5. overview监控上传下

top image

log

火焰图

执行计划



overview 需要哪些

在补个云监控低峰是我关闭节点操作

top
image

heap.profile (116 字节)

  1. 什么时间执行的sql?
  2. 请反馈完整的sql和建表语句,截图里不全
  3. overview监控全部上传下

(1)、chrome 安装这个插件https://chrome.google.com/webstore/detail/full-page-screen-capture/fdpohaocaechififmbbbbbknoalclacl

(2)、鼠标焦点置于 Dashboard 上,按 ?可显示所有快捷键,先按 d 再按 E 可将所有 Rows 的 Panels 打开,需等待一段时间待页面加载完成。

(3)、使用这个 full-page-screen-capture 插件进行截屏保存

语句是可以执行的,就是tidb 的内存回收好慢

我gc 设置成0.1h ,

这两个capacity 设置成0,memory-guard-ratio 0.9。想尽快释放内存

  1. 执行计划里都是pseudo,可以考虑先收集箱统计信息
  2. 你修改的gc主要是tikv,当前内存问题是在tidb.
  3. 总的内存是32G,一个sql即使使用了6G,内存会逐渐下降,也利于下一次同样sql执行的取值,当前担心的主要问题是什么?

你提的第三点确实是如果是olap 业务会很有效,但是,如果是持续的不同语句查询,内存下不来岂不是oom了

CREATE TABLE kernel_send_order ( TenantId int(11) DEFAULT NULL, ShardId int(11) DEFAULT NULL, SendOrderId bigint(20) NOT NULL COMMENT ‘派件订单ID’, ExpressNumber varchar(30) DEFAULT NULL COMMENT ‘快递单号’, ExpressId int(11) DEFAULT NULL COMMENT ‘快递公司ID’, Password varchar(80) DEFAULT NULL COMMENT ‘取件码’, StationId int(20) DEFAULT NULL COMMENT ‘站点ID’, DeviceId int(20) DEFAULT NULL COMMENT ‘设备编号 暂时不用’, DeviceSn varchar(255) DEFAULT NULL COMMENT ‘设备编号’, DeviceType int(11) DEFAULT NULL COMMENT ‘设备类型’, CellId int(11) DEFAULT NULL COMMENT ‘智能柜格口号 暂时不用’, CellSn varchar(255) DEFAULT NULL COMMENT ‘格口号’, CellType int(11) DEFAULT NULL COMMENT ‘格口类型:(1 小格口,2 中格口,3 大格口,4 超大格口)’, ShelfNo varchar(20) DEFAULT NULL COMMENT '入库人工货架编号 ', SendOrderType int(11) DEFAULT NULL COMMENT ‘订单类型 (参见字典SendOrderType)1智能柜 2站点派件’, SendOrderStatus int(11) DEFAULT NULL COMMENT ‘订单状态 1到站 2入库 3出库 没用’, SendOrderStatusType int(11) DEFAULT NULL COMMENT ‘订单状态类型 201货架 301已签收 … 没用’, ArrivePayAmount int(11) DEFAULT NULL COMMENT ‘到付金额(分)’, InsteadPayAmount int(11) DEFAULT NULL COMMENT ‘代付金额(分)’, CreateTime datetime(3) NOT NULL COMMENT ‘创建时间’, UpdateTime datetime(3) DEFAULT NULL COMMENT ‘修改时间’, IsArrive bit(1) DEFAULT NULL COMMENT ‘是否到站’, ArriveTime datetime DEFAULT NULL COMMENT ‘到站时间’, ArriveOperatorId int(11) DEFAULT NULL COMMENT ‘到站操作人’, IsExpressIn bit(1) DEFAULT NULL COMMENT ‘是否入库’, ExpressInType int(11) DEFAULT NULL COMMENT ‘入库类型 201货架 202快递柜 203外送’, ExpressInTime datetime DEFAULT NULL COMMENT ‘入库时间’, ExpressInOperatorId int(11) DEFAULT NULL COMMENT ‘入库操作人’, IsExpressOut bit(1) DEFAULT NULL COMMENT ‘是否出库’, ExpressOutType int(11) DEFAULT NULL COMMENT ‘出库类型 301已签收 302未签收 303拒收 304退回 305转址 306滞留 307延迟派送 308退件交接 309超期回收(快递柜) 310快递员退柜(快递柜) 311站点管理员退柜(快递柜)\r\ 字典类型:ExpressOutType’, ExpressOutTime datetime DEFAULT NULL COMMENT ‘出库时间’, ExpressOutPhoto text DEFAULT NULL COMMENT ‘出库照片’, ExpressOutRemark varchar(255) DEFAULT NULL COMMENT ‘出库备注’, ExpressOutOperatorId int(11) DEFAULT NULL COMMENT ‘出库操作人’, SendOrderAmount int(11) DEFAULT NULL COMMENT ‘订单金额(派件费)’, ExpressOutIdentityCardName varchar(255) DEFAULT NULL COMMENT ‘出库身份证姓名’, ExpressOutIdentityCardNo varchar(255) DEFAULT NULL COMMENT ‘出库身份证号’, ExpressInIdentityCardName varchar(255) DEFAULT NULL, ExpressInIdentityCardNo varchar(255) DEFAULT NULL, ExpressInPhoto text DEFAULT NULL, SubsidiaryCode varchar(10) DEFAULT NULL COMMENT ‘副柜编号’, IsLinger bit(1) DEFAULT NULL COMMENT ‘是否滞留’, LingerTime datetime DEFAULT NULL COMMENT ‘滞留时间’, LingerOperatorId int(11) DEFAULT NULL COMMENT ‘滞留操作人’, ArrivePayType int(11) DEFAULT NULL COMMENT ‘到付支付方式 0无 1现金支付 2扫码支付’, ExpressInClient int(11) DEFAULT NULL, CellLeaseStatus int(11) DEFAULT NULL, BoxLeaseStatus int(11) DEFAULT NULL, PRIMARY KEY (SendOrderId,CreateTime), KEY CreateTime (CreateTime), KEY Express (ExpressId), KEY ExpressNumber (ExpressNumber), KEY Device (DeviceSn), KEY idxUpdateTime (UpdateTime), KEY idxPwd (Password), KEY idxStatus (IsExpressIn,IsExpressOut,IsLinger), KEY idxOprExpress (ExpressInType,ExpressInOperatorId,IsExpressIn,IsExpressOut,ExpressOutOperatorId,ExpressOutType), KEY idxLingerSms (IsExpressIn,ExpressInType,IsLinger,ExpressInOperatorId), KEY idxExpressInTime (ExpressInTime), KEY idxLingerTime (LingerTime), KEY idexExpressOutTime (ExpressOutTime), KEY idxInOpr (ExpressInOperatorId), KEY idxOutOpr (ExpressOutOperatorId), KEY idxArriveOpr (ArriveOperatorId), KEY idxStationExpress (StationId,IsExpressIn,IsExpressOut,ExpressOutType,ExpressInType), KEY idxSendOrderId (SendOrderId), KEY Station (StationId,ExpressId), KEY Tenant (TenantId), KEY idxStationUpdate (StationId,UpdateTime), KEY idxTenantStation (TenantId,StationId,ExpressId) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin PARTITION BY RANGE ( to_days(createtime) ) ( PARTITION p0 VALUES LESS THAN (737060), PARTITION p1 VALUES LESS THAN (737241), PARTITION p2 VALUES LESS THAN (737303), PARTITION p3 VALUES LESS THAN (737364), PARTITION p4 VALUES LESS THAN (737425), PARTITION p5 VALUES LESS THAN (737484), PARTITION p6 VALUES LESS THAN (737545), PARTITION p7 VALUES LESS THAN (737606), PARTITION p8 VALUES LESS THAN (737668), PARTITION p9 VALUES LESS THAN (737729), PARTITION p10 VALUES LESS THAN (737790), PARTITION p11 VALUES LESS THAN (737850), PARTITION p12 VALUES LESS THAN (737911), PARTITION p13 VALUES LESS THAN (737972), PARTITION p14 VALUES LESS THAN (738034), PARTITION p15 VALUES LESS THAN (738095), PARTITION p16 VALUES LESS THAN (738156), PARTITION p17 VALUES LESS THAN (738215), PARTITION p18 VALUES LESS THAN (738276), PARTITION p19 VALUES LESS THAN (738337), PARTITION p20 VALUES LESS THAN (738399), PARTITION p21 VALUES LESS THAN (738460), PARTITION p22 VALUES LESS THAN (738521) );

CREATE TABLE kernel_send_order_extend ( TenantId int(11) DEFAULT NULL, ShardId int(11) DEFAULT NULL, SendOrderId bigint(20) NOT NULL, ReceiverName varchar(150) DEFAULT NULL, ReceiverAddress varchar(200) DEFAULT NULL COMMENT ‘收件人地址’, ReceiverPhone varchar(20) DEFAULT NULL COMMENT ‘收件人手机’, SenderName varchar(20) DEFAULT NULL COMMENT ‘发件人姓名’, SenderPhone varchar(20) DEFAULT NULL COMMENT ‘发件人手机’, SenderAddress varchar(200) DEFAULT NULL COMMENT ‘发件人地址’, Remark varchar(100) DEFAULT NULL, Weight decimal(10,2) DEFAULT NULL, Num int(11) DEFAULT NULL, RejectReason varchar(100) DEFAULT NULL COMMENT ‘拒收原因 没用’, OperatorId int(11) DEFAULT NULL COMMENT ‘操作人Id’, SendTime datetime DEFAULT NULL COMMENT ‘外派时间 没用’, ReceiveTime datetime DEFAULT NULL COMMENT ‘签收时间 没用’, PhotoTime datetime DEFAULT NULL COMMENT ‘拍照时间 没用’, PhotoURL varchar(200) DEFAULT NULL COMMENT ‘出库照片地址 没用’, PhotoStatus smallint(6) DEFAULT NULL COMMENT ‘出库拍照状态:0 未拍照 1已拍照 没用’, OrderPasswordStatus smallint(5) unsigned zerofill DEFAULT ‘00000’ COMMENT ‘订单取件码状态:0 未下发 1 已下发成功 2 终端已成功接收’, SmsSendStatus int(11) DEFAULT NULL COMMENT ‘入库短信发送状态 1未发送 2已发送 3接收成功 4接收失败 5重新发送中 6重发成功 7重发失败’, SmsSendTime datetime DEFAULT NULL COMMENT ‘短信发送时间’, SmsReceivedTime datetime DEFAULT NULL COMMENT ‘短信送达时间’, WxMsgSendStatus int(11) DEFAULT NULL COMMENT ‘微信发送状态 1未发送 2已发送 3接收成功 4接收失败 5重新发送中 6重发成功 7重发失败’, WxMsgSendTime datetime DEFAULT NULL COMMENT ‘微信消息发送时间’, createtime datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, FirstReceiveMsgTime datetime DEFAULT NULL COMMENT ‘通知首次送达时间’, MsgSendStatus int(11) NOT NULL DEFAULT ‘1’ COMMENT ‘消息(取件码)发送状态’, VoiceSendStatus int(11) DEFAULT NULL, VoiceSendTime datetime DEFAULT NULL, PRIMARY KEY (SendOrderId,createtime), KEY Tenant (TenantId,ShardId), KEY CreateTime (createtime), KEY SendOrderId (SendOrderId), KEY ReceiverPhone (ReceiverPhone), KEY MsgSendStatus (MsgSendStatus), KEY WxMsgSendStatus (WxMsgSendStatus), KEY SmsSendStatus (SmsSendStatus), KEY idxMsgStatus (SmsSendStatus,WxMsgSendStatus) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin PARTITION BY RANGE ( to_days(createtime) ) ( PARTITION p0 VALUES LESS THAN (737060), PARTITION p1 VALUES LESS THAN (737241), PARTITION p2 VALUES LESS THAN (737303), PARTITION p3 VALUES LESS THAN (737364), PARTITION p4 VALUES LESS THAN (737425), PARTITION p5 VALUES LESS THAN (737484), PARTITION p6 VALUES LESS THAN (737545), PARTITION p7 VALUES LESS THAN (737606), PARTITION p8 VALUES LESS THAN (737668), PARTITION p9 VALUES LESS THAN (737729), PARTITION p10 VALUES LESS THAN (737790), PARTITION p11 VALUES LESS THAN (737850), PARTITION p12 VALUES LESS THAN (737911), PARTITION p13 VALUES LESS THAN (737972), PARTITION p14 VALUES LESS THAN (738034), PARTITION p15 VALUES LESS THAN (738095), PARTITION p16 VALUES LESS THAN (738156), PARTITION p17 VALUES LESS THAN (738215), PARTITION p18 VALUES LESS THAN (738276), PARTITION p19 VALUES LESS THAN (738337), PARTITION p20 VALUES LESS THAN (738399), PARTITION p21 VALUES LESS THAN (738460), PARTITION p22 VALUES LESS THAN (738521) );

select s., e. from kernel_send_order s join kernel_send_order_extend e on s.SendOrderId=e.SendOrderId where s.StationId=83 and s.DeviceSn=‘637637471812’ and s.IsExpressIn=1 and s.IsExpressOut=0 and s.ExpressInType=202;

语句肯定有问题的。我现在在添加索引看下。然后我有个问题像这条语句,执行计划肯定会对kernel_send_order 这张表结算下推tikv 后获取想要的数据推送到tidb,由tidb 内存存储,同时 join 这张表由于没有赛选,所以会全表内容一起存储到tidb内存中,在进行join 是吗?

当前tidb有类似功能coprocessor cache , 结果会在 tidb 缓存,部分中间结果。 具体看实现。而且数据不能修改过,对于olap场景比较适合. 上个贴这个能关吗

3.0 的确是这样的,目前 3.0 没有 join 中间结果落盘的操作,如果这种大查询来的比较频繁,很大概率 TiDB 会 OOM。4.0 有中间结果落盘,应该会有所缓解

一条语句执行完毕后 TiDB 内存的释放速度取决于 golang runtime 的 gc 速度,如果是 AP 业务的话,在 3.0 的集群上可以试着把 TiDB 所在机器的 swap 打开,一定程度上能够缓解

TiDB 目前没有做查询结果的缓存,每次查询来了以后都会计算一次。另外你说的 coprocessor cache 还没有开发完毕,所以暂时还不能使用(这个是针对 TiKV 端的优化,对降低 TiDB Hash Join 的运行时内存帮助不大)

1 个赞

从执行计划来看,s 表上还可以通过更合适的索引进一步降低内存使用。另外可以把 tidb_distsql_scan_concurrency 和 tidb_hash_join_concurrency 调低,这两个分别是汇总 TiKV 数据和在 TiDB 做 Hash Join 的并发参数,调低他们也对节省内存也有帮助。

TiDB 内存的释放速度取决于 golang runtime 的 gc 速度 ,这个速度是不是基于tidb version版本对应的golang version?

  1. 通过 top 看 go 的内存不释放是符合预期, top 高可能可能是因为第一个查询执行完后有部分内存 go 没还给操作系统,可以通过 tidb 监控 server - memory usage 看“实际占用内存”( go_memstats_heap_sys_bytes{job=“tidb”} - go_memstats_heap_released_bytes{job=“tidb”})

  2. 对于你担心的内存OOM问题, 第二个查询到达需要分配的时候, 第一个运行结束这部分sql,没归还的内存还是可以被第二个查询使用的,所以不会运行第二个 top 不会导致 8 -> 16,可以下看下这篇博客 http://zenlife.tk/go-scavenge.md

  3. gc是go lang的参数,这个不建议修改. 会对性能有影响.

开启swap 后,滚动升级会报错,是否我修改文件跳过即可?