Mysql之InnoDB索引

1.索引简介

官网介绍:MySQL :: MySQL 8.0 Reference Manual :: 10.3.1 How MySQL Uses Indexes

索引用于快速查找具有特定列值的行。如果没有索引, MySQL 必须从第一行开始,然后读取整个表以找到相关的行。表越大,花费就越多。如果表中有相关列的索引,MySQL 可以快速确定数据文件中间要查找的位置,而不必查看所有数据。这比按顺序读取每一行要快得多。

 我们来看一个案例,假设我有一个50w数据的表没有索引的情况下我的查询速度。

当我为product_price字段建立索引后的查询速度

ALTER table product_new ADD INDEX idx_product_price(product_price) -- 建立索引

那么索引究竟是怎么提升性能的呢?

官网:MySQL :: MySQL 8.0 Reference Manual :: 10.3.1 How MySQL Uses Indexes

Most MySQL indexes (PRIMARY KEYUNIQUEINDEX, and FULLTEXT) are stored in B-trees. Exceptions: Indexes on spatial data types use R-trees; MEMORY tables also support hash indexes; InnoDB uses inverted lists for FULLTEXT indexes.

看到这里我们就知道了,索引是存储在B-trees中的,也就是我们所说的B+树,是一种数据结构,那么索引其实就是用空间换时间。单独把偶你一些额外的,能帮助提高检索性能的数据。 

思考: 上面提到了2种数据结构,一种是B+树,一种是hash,区别是什么呢?是不是所有的存储引擎都支持呢?

1.B+tree 支持范围,但是 Hash k-v 的形式,所以不支持范围查询
2. 查询性能,如果等值查询, hash tree 要快很多,还是因为它是 k-v 的hash结构
1.B+tree MyISam memory innoDB 都支持
2.hash 索引只支持 memory InnoDB 有页自适应,但是不是 hash 索引

2.B+树索引

博客Mysql之Innodb存储引擎-CSDN博客 中已经介绍了我们查询数据的时候,会先从内存查询,如果内存没有,会去磁盘获取,内存跟磁盘的最小交互单位是页。页里面存储的是数据行。

那我们举个例子,假如我现在有个表zsc_teacher,这里有18条数据,这些都是行,行我们都会放到page页中,一个页的大小是有限制的,默认16k。我们假设我们的每个页只能存放3条数据,那么这18条数据就需要放到6个页。页里面的数据保存规则是什么呢?

1. 页里面的数据一定要排序,假如默认得根据主键排序,如果没有主键,非空的唯一字段,如果还没有,用隐藏的row_id 排序字段
2. 页中的数据需要是单链表链起来,这样能让我快速的去操作相关数据,链表的操作性能更高,加数据的时候,我只需要更改前后的链表指向就行。
3. 既然需要很多的页,那么页跟页一定要连起来,我得知道这个页的下一个页是哪个,我才能去找,所以页跟页之前是一个双向链表,并且下一个页的最小数据必须大于上一个页的最大数据。

如图所示,我们的zsc_teacher表在页中的存储如下:

 

 每行上面的0代表的是这是一个数据行,假如,我现在要去插id=50的数据,我就需要从第一页开始,遍历6个页。页又是内存跟磁盘的最小交互单位,所以我最多可能需要跟磁盘进行6次IO,页跟 页之间又是一个双向链表的关系,查询性能是O(n),页越多,要查后面的数据遍历的页也就越多。那么索引是怎么提升我们的查询性能的呢?

首先,为每个完整的行数据创建一个目录行,目录行中只保存这个页的最小值以及这个最小值所在的页码,因此,这样依赖,页的空间就多了,因此可能保存的目录行就不止3个了,我们假设此时保存的是4个。

这样一来,我们6个页的数据,就需要2个目录页来保存就可以了,但是2个目录页来保存,想按照树的方式去查询,还是不行,因为没有跟目录,因此依照上面的原理,再建立一个根目录页出来。最终的树形结构如下所示:

 

这样,我们再去查询一遍id=50的数据

1.遍历根目录。 有2条目录数据,50大于44,所以去二级目录的888

2. 遍历 888 页, 50 大于 49 ,去页 22
3. 遍历页 22 的数据,找到 50

 我们发现相比之前遍历的6个页。我现在只需要遍历3个页,并且这3个页是稳定的,因为遍历的页面数就是这棵树的高度。树越高,遍历的页面就越多,树越低,遍历的页数就越少,跟磁盘IO的次数也就越少,性能越高。

B+树索引有哪些优势呢?

1. 叶子节点才会有完整的一行数据,而非叶子节点是目录,非叶子节点的行大小就越小,越小,那能放的数据就越多,数据越多,同样层级的树能容纳的数据也就越多,或者同样的数据量可能需要的树的高度越低,高度越低,磁盘可能IO 的次数越少,性能越高。所以 整体性能比其他树更好
2. 稳定,不管你查什么,因为非叶子结点没有完整的行数据,所以都需要遍历树的高度。
3. 叶子节点是有序并且链表关联,所以可以更好的范围查询跟遍历。

3.索引类型

3.1 聚簇索引、二级索引

主键、聚集、聚簇索引(Clustered Index): 每个InnoDB存储引擎都会有且只有一个Clustered Index索引树,默认以主键排序,如果没有主键,会用非空的唯一字段,非空的唯一字段也没有,就会用隐藏的row_id。

二级索引(secondary Indexes): 除Clustered Index外的单列、多列索引,手动去基于哪些字段建立索引时,会根据这些字段排序创建一个B+树,排序规则先根据第一个字段,第一个字段相等根据第二个,以此类推。 注意: 二级索引不会有完整的行数据,只有索引的字段以及Clustered Index的排序字段。

举例: 以zsc_teacher表为例,假设我建立了一个age字段的索引,就会以age排序建立索引树,后续根据age去查询的时候就会快很多。

如果是多个字段呢?假如我根据age name建立联合索引,则索引树上就会有age、name字段以及clustered Index的排序字段。在索引树的排序规则是先根据a排序,如果a相等,再根据b排序(这就是索引最左匹配的本质),如图所示:

3.2 回表、覆盖索引

回表: 查询走的索引树,不包含我们要查询的字段,需要根据clustered Index的排序字段回到clusterd Index去查询需要的字段。

举例: 比如我们要查询

select * from zsc_teacher where age = 32;

 由于我们查询的是*,是全部数据,因此即使我们age创建了索引,但是我们的二级索引树中只包含了age,name 和id。并没有全部数据,这个时候就需要查到id后,再回表去查询所有的数据,这个过程就叫做回表。

覆盖索引: 查询计划走到的索引树包含了需要查询的字段,不需要回到Clustered Index查询。

举例:

select age,name from zsc_teacher where age = 32;

 这条sql,我们只查询age和name,由于age和name都在二级索引树中,因此我们此时就不需要再去回表操作,这个就叫做覆盖索引

3.3 索引下推

索引下推: 把本来要在server层执行器里过滤的数据,移动到二级索引树(如果二级索引树有相关数据能过滤),从而达到减少回表的次数以及server层跟存储层之间的数据交互的目的。

举例,我们执行这样的一条sql

select * from zsc_teacher where age = 13 and name like '%huihui1'

 

分析: 由于我建立了一个age与name的联合索引,所以age一定是有序的,我这个查询也就肯定能走到age的联合索引,查询age等于13我能查到两条;然后第二个条件,like 百分号开头,由于是百分号开头,所以这个字段肯定是走不到索引的,走不到索引,并且没有索引下推的情况,我会把这两条数据都给到我们的server层,然后server层会去过滤,当然了,在过滤之前,由于查询的是*,因此我会回表两次,再返回给我们的server层。

分析: 有了索引下推以后,虽然还是只有age能够走到我们的索引,name同样的走不到索引,但是由于name这个字段 在我的二级索引里面是有的,既然有,那我就可以在二级索引中把它过滤掉,虽然我根据age还是扫到了两条,但是我可以根据这个二级索引去把这个huihui2给过滤掉,这样我就不需要回表两条,也不需要给到server层两条,所以这个就是索引下推,索引下推的精髓就是把过滤的条件在我们的存储引擎中,基于二级索引去做掉,减少回表的次数以及减少server层跟存储引擎的交互数量。

当然,也可以进行配置 开启或者关闭

set optimizer_switch = 'index_condition_pushdown=off'

set optimizer_switch = 'index_condition_pushdown=on'

 思考: 既然我们了解了索引的原理,那么什么情况下索引会失效呢?

我们举个例子,假如我们建立了一个组合索引a , b , c查询条件 c=10 and a = 1 and b>= 30,是否都会用到索引呢?

联合索引 abc ,在索引树是先根据 a 排序, a 相同的根据 b 排, b 相同的再根据c 排。
首先,最左匹配原则: a where 条件中存在,满足,所以肯定能走到索引树,但是不确定是否所有条件都会走。
继续最左, b b 在条件中也存在,所以 b 也能走到索引。但是 b 是个范围查询,范围查询后,c 就是无序的。

 总结索引失效的场景:

  1. 不满足最左匹配
  2. 范围查询会使下一个索引列失效,因为下一个是无序的
  3. 类型转换,排序规则是不一样
  4. 运算

总之,一句话,走不走索引,其实是索引优化器说了算,索引我们要学会怎么查看执行计划。

4.执行计划分析

   我们要分析sql语句究竟走不走索引,要去看执行计划,怎么看?很简单,explain加上sql语句就行,适用于select、delete、insert、replace、和update等语句

举例: 

explain select * from b_bid_info where id = 3090;

 输出字段的官网介绍: MySQL :: MySQL 8.0 Reference Manual :: 10.8.2 EXPLAIN Output Format

select_type: 查询类型 

partitions: 分区,查询语句要走哪些分区 MySQL :: MySQL 8.0 Reference Manual :: 26.3.5 Obtaining Information About Partitions

type: 连接类型 MySQL :: MySQL 8.0 Reference Manual :: 10.8.2 EXPLAIN Output Format

system( 特例 const, 系统表中只有 1 ) const eq_ref ref fulltext 、ref_or_null、 index_merge unique_subquery index_subquery 、range、 index ALL

 我们的执行计划最好能达到range,如果达不到,就要进行优化

possible_keys: 可以选择的索引查询,如果为null 则没有索引可供选择

key: 真正使用到的索引

key_len: 使用的键的长度

ref: 索引引用关系

rows: 执行查询必须扫描的行数,对于innodb来讲,这是个预估值,不是非常准确

filtered: 行数据过滤百分比

Extra:MySQL :: MySQL 8.0 Reference Manual :: 10.8.2 EXPLAIN Output Format

5.索引优化案例

5.1 count优化

count是一个聚合函数,对于返回的结果集是一行一行去判断统计的,如果count括号里的不是null,那么累计值+1,否则不加,最后返回一个累计的总数。

括号里的字段选择:

count 括号里的参数应该是 id 、还是字段、还是 1 、还是 *
1. * 是整条数据,也进行了优化,因为整条数据肯定不会为 null 。所以也不需要去判断
2. count(id , 主键 id ,肯定不为 null ,也不会去判断 null, 但是相对于count(1)来讲,要去解析 ID. 稍微慢点,但是也可以忽略不计
3. count( 字段),如果字段没有索引,就需要进行全表扫描, explain 是all; 如果字段不为 null ,那么不需要进行 null 逻辑判断,如果可为空,则每条数 据要进行非空判断
总结: count(1) 约等于 count(*) > count(id) > count(字段),字段是否有索引,是否可为Null,也会影响性能。 

5.2 limit优化

limit m,n; 其实去扫描m+n条数据,然后过滤掉前面的m条数据,当m越大,那么需要扫描的数据也就越多,性能也会越来越慢。

EXPLAIN SELECT * FROM product_new LIMIT 300000,10 -- 很慢很慢
EXPLAIN SELECT * FROM product_new ORDER BY id LIMIT300000,10
 -- 需要添加排序条件 就能走到id的索引

针对这种情况,有以下几个方案可以进行优化

 1.如果id是趋势递增的,那么每次查询都可以返回这次查询最大的ID,然后下次查询,加上大于 上次最大id的条件,这样会通过主键索引去扫描,并且扫描数量会少很多很多。因为只需要扫描where条件的数据

SELECT * FROM product_new WHERE id>300396 ORDER BY id LIMIT 10 
-- 根据id查询,并且使用where过滤

 2.先limit出来主键ID,然后用主表跟查询出来的ID进行inner join 内连接,这样,也能一定上提速,因为减少了回表,查询ID只需要走聚集索引就行。

SELECT * FROM product_new INNER JOIN
(
SELECT id FROM product_new ORDER BY id LIMIT 300000,10
) a
ON product_new.id=a.id

 3.当然,如果mysql级别优化不了了。我们也可以对分页数据进行缓存,比

Redis 缓存,数据进行变动的时候,做好缓存依赖即可

 4.因为越往后,一般用户行为触及不到,比如你去看淘宝,不会去翻后面几

百页的数据,所以,业务层面也可以做一些让步,最多展示多少页。

5.3 order by优化

官网介绍: MySQL :: MySQL 8.0 Reference Manual :: 10.2.1.16 ORDER BY Optimization

如果让 orderby 的字段走索引,那么排序流程直接可以在索引树完成,如果排序的字段不走索引,整个排序流程必须先把数据放到内存,在内存实现排序。这个内存的大sort_buffer_size 配置 , 如果内存不够保存这个数据,那么就会启用磁盘的临时文件来进行排序。

 怎么判断orderby是否用到了索引?

如果输出 Extra 的列 EXPLAIN 不包含 Using filesort ,则使用索引
如果输出 Extra EXPLAIN 包含 Using filesort ,则不使用索引

5.4 group by优化

官网介绍: MySQL :: MySQL 8.0 Reference Manual :: 10.2.1.17 GROUP BY Optimization

首先,我们先看下group by如果没有走到索引的实现流程

1. 会将符合条件的数据扫描后,放到一个临时表,并且这个临时表是根据group by的字段排序好的
2. 然后在临时表根据用户的聚合需求,比如是求 count sum, 返回给用户相关结果

 举例: 

EXPLAIN SELECT SUM(product_type), product_count FROM
product_new WHERE product_type=6 GROUP BY product_count;

分析: product_type属于一个索引,product_count属于另外一个索引。会先通过product_type索引拿到结果,然后放入临时表中进行分组处理。结果,用到了临时表

 

 但是如果groupby写得够好,那么就可以避免创建临时表的逻辑,让直接通过索引来group by。防止group by去创建临时表,有2种场景: loose index scan(松散索引)和tight index scan(紧密索引),感兴趣的想深入研究的可以去官网上查看,有具体的实例

6.慢查询及优化

6.1 慢日志参数

是否开启慢查,默认情况是关闭的

SET GLOBAL slow_query_log=1; -- 开启慢查

 慢时间,必须超过这个值才是慢查

SELECT @@long_query_time; -- 默认是10 单位s
SET GLOBAL long_query_time=1; -- 设置超过1s就算慢查

检索数量,检索查询数量的行如果低于这个值,不进入慢查

SELECT @@min_examined_row_limit; -- 默认是 0

 慢查默认不包括管理语句,比如创建表、创建索引等等

SELECT @@log_slow_admin_statements;
SET GLOBAL log_slow_admin_statements=1; -- 开启

 默认也不记录不使用索引的慢查

SELECT @@log_queries_not_using_indexes;
SET @@GLOBAL.log_queries_not_using_indexes=1; -- 开启

日志保存方式,FILE或table,也可以table,file或者null,代表禁用日志写入

SELECT @@log_output; -- 慢查存在哪里
SET GLOBAL log_output='table,file'; -- 比如我希望2边都保存

 比如添加到file

SELECT @@slow_query_log_file;
SET GLOBAL slow_query_log_file='/var/lib/mysql/huihuislow.log';

如果是表,则保存在mysql.slow_log表中

6.2 慢日志分析

表分析:

查询 mysql.slow_log 表,慢查在我们的慢查表中

 

 我们发现,sql_text是一些二进制,我们需要给它转码一下

SELECT *,CONVERT(sql_text using utf8) FROM slow_log

文件分析:MySQL :: MySQL 8.0 Reference Manual :: 6.6.10 mysqldumpslow — Summarize Slow Query Log Files

 官网中有提供慢查分析的指令,mysqldumpslow

6.3 mysql优化

a.硬件层面优化,我们知道Mysql最重要的瓶颈在磁盘的io,所以硬件层面,最终的其实就是磁盘

1. 提高磁盘读写能力,可以用比较新型的磁盘
2. 减少寻址时间,可以横向扩展,将数据添加到不同的磁盘,每个磁盘数据的寻址通常1s 100 次寻址,那么单个磁盘有限制,就多个磁盘寻址
3. 当然,除了磁盘以外, cpu 、内存以及带宽也是比较重要的因素; 增加服务器资源
部署主从、多主多从等集群

b 数据库层面优化

b.1 表结构优化

1.字段类型 尽可能使用最小的并且满足业务场景的数据类型,这样行数据占用的内存越小,索引树越矮,磁盘IO 次数越低。同时尽量避免 null字段出现,可以指定默认值,减少判断null 的开销,因为有 null 的时候,索引需要对null 进行单独处理
2.合适的存储引擎
3.分库分表;
横向拆分,就统一的业务表 数据量可能会很大,为了减少单表的压力,比如产品表 分为产品表1 2 3;
纵向拆分 则是业务相对独立的模块 单独拆分表。以及表字段过多的时候,会进行分表。

b2.Innodb存储引擎优化

1. 增加 bufferpool 大小
bufferpool 我们知道是 innodb 里面缓存数据的内存区间,默认大小为
128M bufferpool 越大,那么内存能放的数据越大,这样,查询数据去磁
盘查询的次数也就越少。
2. 增加重做日志大小

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/642025.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ES基础概念

本文不介绍如何使用ES(使用ES见:) 1.ES生态圈 ES: Logstash:数据处理服务程序,解析转换加工数据; Kibana:数据展示、集群管理,数据可视化、ES管理与监控、报表等&#xf…

推荐一个快速开发接私活神器

文章目录 前言一、项目介绍二、项目地址三、功能介绍四、页面显示登录页面菜单管理图表展示定时任务管理用户管理代码生成 五、视频讲解总结 前言 大家好!我是智航云科技,今天为大家分享一个快速开发接私活神器。 一、项目介绍 人人开源是一个提供多种…

Java反射角度简单理解spring IOC容器

概述 Java反射(Reflection)是Java编程语言的一个特性,它允许在运行时对类、接口、字段和方法进行动态查询和操作。反射提供了一种在运行时查看和修改程序行为的能力,这通常用于实现一些高级功能,如框架(Spring)、ORM&…

Git简介以及下载安装和配置

Git介绍 什么是版本控制?什么是Git?什么是集中式版本控制(了解)分布式版本控制工作流程 Git的安装与配置注册邮箱以及用户名(方便远程使用)初始化项目Git在ideal上的使用(本地) 什么是版本控制? ​ 版本控制是指对软件开发过程中各种程序代码,控制文件及说明文档等文件变更…

《计算机网络微课堂》1-3 三种交换方式

本节课我们介绍三种交换方式,分别是电路交换(Circuit Switching),分组交换(Packet Switching)以及报文(Message Switching)交换。 我们首先来看电路交换,在电话问世后不…

设计模式8——原型模式

写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用,主要是下面的UML图可以起到大作用,在你学习过一遍以后可能会遗忘,忘记了不要紧,只要看一眼UML图就能想起来了。同时也请大家多多指教。 原型模式(Prototyp…

MiniCPM-Llama3-V-2_5-int4

MiniCPM-Llama3-V-2_5-int4大模型部署使用环境: python3.8cuda11.8其它要求,按照安装文档要求下载即可 我是在算力平台用4090跑的, GPU 显存(8GB)可以部署推理 int4 量化版本,如果推理非量化版本需要更高显…

开视频号小店要花哪些钱?这些费用大家要知道

大家好,我是喷火龙。 目前,视频号小店从推出到现在已经快两年的时间了,视频号小店虽然门槛高,但是单价也高,利润也高,市场环境也好,算是一个不错的项目。 接下来给大家讲讲开视频号小店要花哪…

推荐五个线上兼职,在家也能轻松日入百元,适合上班族和全职宝妈

在这个瞬息万变的时代,你是否也曾考虑过在繁忙的工作之外,寻找一份兼职副业来补贴家用,同时保持生活的多样性?别急,现在就让我为你揭秘五个可靠的日结线上兼职岗位,助你轻松迈向财务自由之路! 一…

VBA批量合并带有图片、表格与文本框的Word

本文介绍基于VBA语言,对大量含有图片、文本框与表格的Word文档加以批量自动合并,并在每一次合并时添加分页符的方法。 在我们之前的文章基于Python中docx与docxcompose批量合并多个Word文档文件并逐一添加分页符(https://blog.csdn.net/zhebu…

iBarcoder for Mac v3.15.1中文激活版:让条形码生成变得如此简单

在现代社会,条形码无处不在,从超市商品到物流包裹,都离不开它的身影。iBarcoder for Mac作为一款简单易用的条形码生成软件,让条形码的生成变得如此简单。 iBarcoder for Mac v3.15.1中文激活版下载 无论你是需要为商品添加条形码…

信息安全等级保护测评: 登陆日志

文章目录 引言I 登录日志表结构设计II 日志处理2.1 封装日志入库2.2 收集登陆信息2.3 查询接口引言 等保测评是信息安全等级保护测评的简称,是对信息和信息载体按照重要性等级分级别进行检测、评估的过程。 背景:近期AIS监控平台(网页版)等保测评,发现没有登陆日志,现要…

【高时效通路】

一 高时效通路 1.1 pathchdumper 实时数据拉取、实时数据处理、5分钟微批dump来加速时效性,具体来说: 实时数据拉取(Fetcher):基于Databus Fetcher基建,直接对接F0层实时拉取最新数据,保证该…

微服务架构-链式微服务设计模式

微服务架构-链式微服务设计模式 链式微服务设计模式(Chain Microservice Pattern)是一种微服务架构中的设计模式,它强调将一系列的服务按照特定的业务逻辑顺序串联起来,形成一个服务链。每个服务在链中负责完成特定的业务功能&am…

基于JSP/Servlet校园二手交易平台(二)

目录 2 开发技术及开发环境 2.1 Java语言简介 2.2 J2EE技术介绍 2.3 Servlet/JSP技术 2.4 MVC 简介 2.5 Struts 技术 2.6 Hibernate 技术 2.6.1 应用程序的分层体系结构 2.6.2 Hibernate的应用及API简介 2.7 开发环境及环境配置 2.7.1 Java/JSP系统环境 2.7.2 JSP环…

uniapp 对接 微信App/支付宝App 支付

相关文档:uni.requestPayment(OBJECT) | uni-app官网 示例代码: import qs from qsasync aliPay(){const { provider } await uni.getProvider({ service:payment })if(provider.includes(alipay)){uni.request({url:后端接口地址,data:{ //传参 },suc…

Rabbitmq 搭建使用案例 [附源码]

Rabbitmq 搭建使用案例 文章目录 RabbitMQ搭建docker 代码golang生产者消费者 可视化消费进度 RabbitMQ搭建 docker docker run -d --hostname rabbitmq --name rabbitmq -e RABBITMQ_DEFAULT_USERadmin -e RABBITMQ_DEFAULT_PASSadmin -e RABBITMQ_DEFAULT_VHOSTmy_vhost -e…

分类预测 | Matlab实现ZOA-SVM斑马算法优化支持向量机的多变量输入数据分类预测

分类预测 | Matlab实现ZOA-SVM斑马算法优化支持向量机的多变量输入数据分类预测 目录 分类预测 | Matlab实现ZOA-SVM斑马算法优化支持向量机的多变量输入数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现ZOA-SVM斑马算法优化支持向量机的多变量输…

5. C++网络编程-UDP协议的实现

UDP是无连接的。 UDP Server网络编程基本步骤 创建socket,指定使用UDP协议将socket与地址和端口绑定使用recv/send接收/发送数据 由于UDP是无连接的,直接侦听就行使用close关闭连接 这个UDP接收数据的时候用的API是recvfrom,发送数据是sendto 客户端 …

IS-IS链路状态数据库

原理概述 一个OSPF链路状态数据库是若干条LSA的集合。与此相似,一个IS-IS链路状态数据库是由若干条LSP的集合。与OSPF链路状态数据库不同,IS-IS链路状态数据库有Level-1和Level-2之分。 在IS-IS协议中,每一条LSA都有一条剩余生存时间、一个…