MySQL 优化总结

目标知识

MySQL执行流程图

MySQL 优化成本路线图

  • 优化成本:硬件>系统配置>数据库表结构>SQL及索引。
  • 优化效果:硬件<系统配置<数据库表结构<SQL及索引。

MySQL 五大优化原则

  • 减少数据返回:设置合理字段数据类型、启用压缩(1、MySQL客户端和MySQL服务器传输数据量太大,需要进行压缩减少带宽。2、MySQL 某几张表太大,需要将表压缩减少磁盘空间占用。3、MySQL表中特定字段过大,需要针对特定字段压缩。)、通过索引访问等方式减少磁盘IO。
  • 返回更少数据:返回业务所需要字段、设置数据分页以减少磁盘IO和网络IO。
  • 减少交互次数:批量执行DML操作/增删改查、使用自定义函数和存储过程以减少与MySQL服务器交互。
  • 减少MySQL服务器CPU开销:尽量避免数据库表的排序操作以及全表扫描查询,减少MySQL 服务器CPU和内存占用。
  • 拓展资源:使用分表操作、分库分表操作、增加并行操作,最大程度使用CPU资源。

总结来说:

  1. 查询尽量命中索引
  2. 尽量避免全部扫描
  3. 移除无效字段查询

select 语句执行顺序

select 语法格式

SELECT
DISTINCT <select_list>
FROM <left_table>
<join_type> JOIN <right_table>
ON <join_condition>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
ORDER BY <order_by_condition>
LIMIT <limit_number>

执行顺序

FROM<表名> # 选取表,将多个表数据通过笛卡尔积变成一个表。

ON<筛选条件> # 对笛卡尔积的虚表进行筛选

JOIN <join, left join, right join...>

<join表> # 指定join,用于添加数据到on之后的虚表中,例如left join会将左表的剩余数据添加到虚表中

WHERE<where条件> # 对上述虚表进行筛选

GROUP BY<分组条件> # 分组

HAVING<分组筛选> # 对分组后的结果进行聚合筛选,<SUM()等聚合函数> # 用于having子句进行判断,在书写上这类聚合函数是写在having判断里面的

SELECT<返回数据列表> # 返回的单列必须在group by子句中,聚合函数除外

DISTINCT数据除重

ORDER BY<排序条件> # 排序

LIMIT<行数限制>

SQL 优化策略实战

温馨提示:SQL优化策略适用于查询数据量较大或单表数据量较大的场景下,如果数据量较小,没必要以此为准。

1、避免不走索引场景 

避免在字段开头模糊查询,会导致数据库引擎放弃索引进行全表扫描。

示例如下:

select * from t_user t where t.name like '%周%' 

优化建议:尽量在字段后面使用模糊查询

select * from t_user t where t.name like '周%'

优化建议和解释如下:

  1. 将 %周% 改为 '周%':在 SQL 查询中,尽量避免使用 % 作为 LIKE 操作符的开头,这样会导致数据库无法使用索引,强制数据库做全表扫描,影响查询性能。将 %周% 改为 '周%' 可以有效利用索引,提高查询性能。

  2. 添加索引:如果表 t_user 的 name 字段没有索引,可以考虑为 name 字段添加索引,从而加快 LIKE 操作的性能。在此案例中,由于 WHERE 子句中对 name 字段进行了模糊查询,添加索引可以显著提升查询性能。

尽量避免使用in 和not in,会导致引擎走全表扫描。

示例如下:

select * from t_user t where t.id in (1, 2)

优化一建议:使用or 查询替换in 查询

select * from t_user t where t.id = 1 or t.id = 2

优化建议和解释:

原始的 SQL 查询语句使用了 IN 子句来查询指定的 id,而优化后的 SQL 查询语句使用 OR 来连接多个 id 的条件,这样数据库在执行查询时可以更有效地利用索引。

使用 OR 来连接多个 id 的条件可以让数据库优化器更好地进行索引选择,避免了 IN 子句可能导致的全表扫描。此外,OR 连接条件时也可以让优化器更好地使用联合索引。

因此,将 IN 子句替换为 OR 来连接多个条件是一个简单却有效的 SQL 查询优化方法。

优化二建议:如果是连续性数字,可以考虑使用between *** and 代替

select * from t_user t where t.id between 1  and 2

示例如下:

select * from t_user t where t.orgId in (select id from t_org o where o.isDelete = 1)

优化一建议:使用内联查询替换in 查询

select t.* from t_user t 
join t_org o on t.orgId = o.id 
where o.isDelete = 1

优化建议和解释:

  1. 原查询中使用了子查询来获取符合条件的 orgId,这样的写法会导致多次查询数据库,效率较低。我们可以通过使用 JOIN 来连接 t_user 表和 t_org 表来实现同样的功能,避免重复查询。
  2. 使用 JOIN 来连接两个表,可以利用索引来加速查询。在这个情况下,我们可以为 t_org 表的 isDelete 字段创建索引,这样在执行 JOIN 操作时能够更快地定位符合条件的数据。
  3. 尽量避免在查询条件中使用函数或者子查询,这样会增加查询的复杂度和开销,影响查询性能。通过将条件拆分成简单的等值条件,可以提高查询效率。

优化二建议:使用existe 函数 替换 in 查询

select * from t_user t where exists (select 1 from t_org o where o.id = t.orgId and o.isDelete = 1)

尽量避免使用 or,会导致数据库引擎放弃索引进行全表扫描。

示例如下:

SELECT * FROM t WHERE id = 1 OR id = 3

优化建议:使用union 代替or

SELECT * FROM t WHERE id = 1UNION
SELECT * FROM t WHERE id = 3

尽量避免进行null值的判断,会导致数据库引擎放弃索引进行全表扫描。

示例如下:

SELECT * FROM t WHERE t.phone is null

优化建议:给字段添加默认值'',对字段取值=''进行判断。

SELECT * FROM t WHERE t.phone =''

尽量避免在where条件中等号的左侧进行表达式、函数操作,会导致数据库引擎放弃索引进行全表扫描。

示例如下:

SELECT * FROM t_score t WHERE t.score/10 = 9

优化建议:左侧表达式运算移动至右侧

SELECT * FROM t_score t WHERE t.score = 10*9

当数据量大时,避免使用where 1=1的条件。通常为了方便拼装查询条件,我们会默认使用该条件,数据库引擎会放弃索引进行全表扫描。

示例如下:

SELECT username, age, sex FROM t_user WHERE 1=1

优化建议:代码拼装sql时进行判断,没 where 条件就去掉 where 1= 1,有where条件就加 and。

SELECT username, age, sex FROM t_use

查询条件不能用 <> 或者 !=

示例如下:

SELECT username, age, sex FROM T WHERE  t.id != 1

优化建议:使用大于(>)操作符替换!=

SELECT username, age, sex FROM T WHERE  t.id > 1

优化建议和解释如下:

  1. 尽量避免在 WHERE 子句中使用不等于(!=)操作符,因为对不等于操作符的查询往往需要进行全表扫描,性能较差。改为使用大于(>)操作符可以更好地利用索引。

示例如下:

SELECT username, age, sex FROM T WHERE  t.username != 'root'

优化建议和解释如下:

  1. 考虑给关联字段(在本例中是 username 字段)添加索引:确保表 T 的 id 字段上有索引,可以加快查询速度。

where条件仅包含复合索引非前置列

示例:复合(联合)索引包含key_part1,key_part2,key_part3三列,但SQL语句没有包含索引前置列"key_part1",按照MySQL联合索引的最左匹配原则,不会走联合索引。

select * from table where key_part2=1 and key_part3=2

隐式类型转换造成不使用索引

SQL语句由于索引对列类型为varchar,但给定的值为数值,涉及隐式类型转换,造成不能正确走索引。

select * from table where col_varchar=123; 

order by 条件要与where中条件一致,否则order by不会利用索引进行排序

-- 不走age索引
SELECT * FROM t order by age;-- 走age索引
SELECT * FROM t where age > 0 order by age;

正确使用hint优化语句

MySQL中可以使用hint指定优化器在执行时选择或忽略特定的索引。

  • use index 在你查询语句中表名的后面,添加 USE INDEX 来提供希望 MySQL 去参考的索引列表,就可以让 MySQL 不再考虑其他可用的索引。例子: SELECT col1 FROM table use index (mod_time, name)...
  • ignore index 如果只是单纯的想让 MySQL 忽略一个或者多个索引,可以使用 IGNORE INDEX 作为 Hint。例子: SELECT col1 FROM table ignore index (priority) ...
  • force index 为强制 MySQL 使用一个特定的索引,可在查询中使用FORCE INDEX 作为Hint。例子: SELECT col1 FROM table FORCE INDEX (mod_time)

SELECT语句其他优化

避免出现select * 

避免出现不确定结果的函数

特别是针对主从复制这类业务场景,由于原理上从库复制的是主库执行的语句,使用如now()、rand()、sysdate()、current_user()等不确定结果的函数很容易导致主库与从库相应的数据不一致。

多表关联查询时,小表在前,大表在后。

在MySQL中,执行 from 后的表关联查询是从左往右执行的(Oracle相反),第一张表会涉及到全表扫描,所以将小表放在前面,先扫小表,扫描快效率较高,在扫描后面的大表,或许只扫描大表的前100行就符合返回条件并return了。

示例:表1有1000条数据,表2有500万条数据;如果全表扫描表2,SQL会提示超时异常。

使用表的别名

当在SQL语句中连接多个表时,请使用表的别名并把别名前缀于每个列名上。减少列名歧义引起的语法错误。

调整Where字句中的连接顺序

MySQL采用从左往右,自上而下的顺序解析where子句。根据这个原理,应将过滤数据多的条件往前放,最快速度缩小结果集。

DML /增删改查语句优化

大批量数据插入

如果同时执行大量的插入,建议使用批量插入INSERT语句,这比循环插入INSERT语句快,性能提示主要体现减少与MySQL 服务器交互次数。

避免重复查询更新的数据

在实际业务开发中经常出现的更新行同时又希望获得改行信息的需求,MySQL并不支持PostgreSQL那样的update teturning语法,在MySQL中可以通过变量实现。

示例如下:更新一行记录的时间戳,同时希望查询当前记录中存放的时间戳。

Update t set time=now() where id=1; Select time from t where id =1; 

优化建议:使用MySQL变量,重写上述功能

Update t set time=now () where id =1 and @now: = now (); Select @now;

前后二者都需要两次网络来回,但使用变量避免了再次访问数据表,特别是当t表数据量较大时,后者比前者快很多。

查询优先还是更新(insert、update、delete)优先

MySQL 允许改变语句调度优先级,它可以使来自多个客户端的查询更好地协作,这样单个客户端就不会由于锁定而等待很长时间。改变优先级还可以确保特定类型的查询被处理得更快。我们首先应该确定应用的类型,判断应用是以查询为主还是以更新为主的,是确保查询效率还是确保更新的效率,决定是查询优先还是更新优先。下面我们提到的改变调度策略的方法主要是针对只存在表锁的存储引擎,比如 MyISAM 、MEMROY、MERGE,对于Innodb 存储引擎语句的执行是由获得行锁的顺序决定的。MySQL 的默认的调度策略可用总结如下:

  1. 写入操作优先于读取操作。
  2. 对某张数据表的写入操作某一时刻只能发生一次,写入请求按照它们到达的次序来处理。
  3. 对某张数据表的多个读取操作可以同时地进行。MySQL 提供了几个语句调节符,允许你修改它的调度策略
  • LOW_PRIORITY关键字应用于DELETE、INSERT、LOAD DATA、REPLACE和UPDATE;
  • HIGH_PRIORITY关键字应用于SELECT和INSERT语句;
  • DELAYED关键字应用于INSERT和REPLACE语句。

如果写入操作是一个 LOW_PRIORITY(低优先级)请求,那么系统就不会认为它的优先级高于读取操作。在这种情况下,如果写入者在等待的时候,第二个读取者到达了,那么就允许第二个读取者插到写入者之前。只有在没有其它的读取者的时候,才允许写入者开始操作。这种调度修改可能存在 LOW_PRIORITY写入操作永远被阻塞的情况。

SELECT 查询的HIGH_PRIORITY(高优先级)关键字也类似。它允许SELECT 插入正在等待的写入操作之前,即使在正常情况下写入操作的优先级更高。另外一种影响是,高优先级的 SELECT 在正常的 SELECT 语句之前执行,因为这些语句会被写入操作阻塞。如果希望所有支持

LOW_PRIORITY 选项的语句都默认地按照低优先级来处理,那么 请使用--low-priority-updates 选项来启动服务器。通过使用 INSERTHIGH_PRIORITY 来把 INSERT 语句提高到正常的写入优先级,可以消除该选项对单个INSERT语句的影响。

查询条件优化

对于复杂的查询,使用中间临时表暂存数据

优化group by语句

默认情况下,MySQL 会对GROUP BY分组的所有值进行排序,如 “GROUP BY 字段1,字段2,....;” MySQL 同时开启隐藏排序,如 “ORDER BY 字段1,字段2,...;”

查询如果包括 GROUP BY 但你并不想对分组的值进行排序,你可以指定 ORDER BY NULL禁止排序。示例如下:

SELECT 字段1, 字段2, COUNT(*) FROM table GROUP BY  字段1, 字段2 ORDER BY NULL ;

优化join语句

MySQL中通过子查询使用 SELECT 语句来实现一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中。使用子查询可以一次性的完成很多逻辑上需要多个步骤才能完成的 SQL 操作,同时也可以避免事务或者表锁死,并且写起来也很容易。但是,有些情况下,子查询可以被更有效率的连接(JOIN)替代。

示例如下:

select * from t_user t where t.orgId in (select id from t_org o where o.isDelete = 1)

优化一建议:使用内联查询替换in 查询

select t.* from t_user t 
join t_org o on t.orgId = o.id 
where o.isDelete = 1

优化union查询

MySQL通过创建并填充临时表的方式来执行union查询。除非确实要消除重复的行,否则建议使用union all。原因在于如果没有all这个关键词,MySQL会给临时表加上distinct选项,这会导致对整个临时表的数据做唯一性校验,这样做的消耗相当高。

示例如下:

select id, name, age t where t.id= 1
union
select id, name, age b where b.id= 2

优化建议:

select id, name, age t where t.id= 1
union all
select id, name, age b where b.id= 2

拆分复杂SQL为多个小SQL,避免大事务

  • 简单的SQL容易使用到MySQL的QUERY CACHE;
  • 减少锁表时间特别是使用MyISAM存储引擎的表;
  • 可以使用多核CPU。

使用truncate代替delete

当删除全表中记录时,使用delete语句的操作会被记录到undo块中,删除记录也记录binlog,当确认需要删除全表时,会产生很大量的binlog并占用大量的undo数据块,此时既没有很好的效率也占用了大量的资源。

使用truncate替代,不会记录可恢复的信息,数据不能被恢复。也因此使用truncate操作有其极少的资源占用与极快的时间。另外,使用truncate可以回收表的水位,使自增字段值归零。

使用合理的分页方式以提高分页效率

使用合理的分页方式以提高分页效率 针对展现等分页需求,合适的分页方式能够提高分页的效率。

select * from t 
where id = 10000 and is_deleted = 0 
order by create_time asc 
limit 0, 15

该种写法缺陷:越翻到后面执行效率越差,时间越长,尤其表数据量很大的时候。

优化建议:

select t.* from (select id from t where t.id = 10000 and t.is_deleted = 0order by t.create_time asc limit 0, 15) a, t where a.id = t.id;

建表优化

  • 在表中建立索引,优先考虑where、order by使用到的字段。
  • 尽量使用数字型字段(如性别,男:1 女:2),若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。
  • 查询数据量大的表 会造成查询缓慢。可以通过合理分页查询来解决。
  • 用varchar/nvarchar 代替 char/nchar

       尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。不要以为 NULL 不需要空间,比如:char(100) 型,在字段建立时,空间就固定了, 不管是否插入值(NULL也包含在内),都是占用 100个字符的空间的,如果是varchar这样的变长字段, null 不占用空间。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++——list类及其模拟实现

前言&#xff1a;这篇文章我们继续进行C容器类的分享——list&#xff0c;也就是数据结构中的链表&#xff0c;而且是带头双向循环链表。 一.基本框架 namespace Mylist {template<class T>//定义节点struct ListNode{ListNode<T>* _next;ListNode<T>* _pre…

京东云16核64G云服务器租用优惠价格500元1个月、5168元一年,35M带宽

京东云16核64G云服务器租用优惠价格500元1个月、5168元一年&#xff0c;35M带宽&#xff0c;配置为&#xff1a;16C64G-450G SSD系统盘-35M带宽-8000G月流量 华北-北京&#xff0c;京东云活动页面 yunfuwuqiba.com/go/jd 活动链接打开如下图&#xff1a; 京东云16核64G云服务器…

算法四十天-删除排序链表中的重复元素

删除排序链表中的重复元素 题目要求 解题思路 一次遍历 由于给定的链表是排好序的&#xff0c;因此重复的元素在链表中的出现的位置是连续的&#xff0c;因此我们只需要对链表进行一次遍历&#xff0c;就可以删除重复的元素。 具体地&#xff0c;我们从指针cur指向链表的头节…

Netty学习 应用Demo之“自动回复”聊天业务

Netty实现自动回复步骤 主要分成五步 1、创建EventLoopGroup实现循环组 管理EventLoop线程 2、创建Bootstrap &#xff0c;Bootstrap对于服务端而言&#xff0c;先后设置其中的线程组group、通道channel、处理器handler、客户端通道对应的处理器childHandler 3、自定义服务器接…

C#操作MySQL从入门到精通(6)——对查询数据进行排序

前言 在和MySql数据库交互的过程中,查询数据是使用最频繁的操作,并且我们经常需要对查询到的数据进行排序后输出,比如我想查询1列数据的最小值,那么我可以将查询到的数据进行升序(从小到大)排列,然后取第一个数据就是最小值。本文详细介绍了对查询数据进行排序的各种操…

HarmonyOS4-Stage模型

Stage模型介绍【舞台模型】&#xff1a; Stage模型 应用配置文件 全局应用配置文件&#xff1a; 模块配置文件&#xff1a; Ability生命周期 页面及组件的生命周期&#xff1a; 启动模式&#xff1a; "launchType": "multiton" // 会重新建&#xff0c…

本地项目提交 Github

工具 GitIdeaGithub 账号 步骤 使用注册好的 Github 账号&#xff0c;登陆 Github&#xff1b; 创建 Repositories (存储库)&#xff0c;注意填写图上的红框标注&#xff1b; 创建完成之后&#xff0c;找到存储库的 ssh 地址或 https 地址&#xff0c;这取决于你自己的配置…

matlab:有限差分求解纳维尔(Navier)边界的双调和(Biharmonic)方程,边值为零

我们考虑如下形式的双调和方程的数值解 其中&#xff0c;Ω是欧氏空间中的多边形或多面体域&#xff0c;在其中&#xff0c;d为维度&#xff0c;具有分段利普希茨边界&#xff0c;满足内部锥条件&#xff0c;f(x) ∈ L2(Ω)是给定的函数&#xff0c;∆是标准的拉普拉斯算子。算…

javaScript手写专题——实现instanceof/call/apply/bind/new的过程/继承方式

目录 原型链相关 手写instanceof 实现一个_instance方法&#xff0c;判断对象obj是否是target的实例 测试 手写new的过程 实现一个myNew方法&#xff0c;接收一个构造函数以及构造函数的参数&#xff0c;返回构造函数创建的实例对象 测试myNew方法 手写类的继承 ES6&…

【单片机】PMS5003,PM2.5传感器数据读取处理

文章目录 传感器介绍数据处理解析pm2.5的代码帮助、问询 传感器介绍 PMS5003是一款基于激光散射原理的数字式通用颗粒物浓度传感器,可连续采集 并计算单位体积内空气中不同粒径的悬浮颗粒物个数,即颗粒物浓度分布,进而 换算成为质量浓度,并以通用数字接口形式输出。本传感器可…

3D Web轻量化引擎HOOPS Commuicator如何从整体装配中创建破碎的装配零件和XML?

前言 虽然可以从某些本机CAD格式&#xff08;其子组件驻留在单独的文件中&#xff0c;例如CATIA V5、Creo - Pro/E、NX或SolidWorks&#xff09;创建破碎装配&#xff0c;但无法从整体装配文件&#xff08;例如IFC、Revit&#xff09;创建或3DXML。 本文介绍了一个示例&#…

12.C++常用的算法_遍历算法

文章目录 遍历算法1. for_each()代码工程运行结果 2. transform()代码工程运行结果 3. find()代码工程运行结果 遍历算法 1. for_each() 有两种方式&#xff1a; 1.普通函数 2.仿函数 代码工程 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<vect…

基于拉格朗日分布算法的电动汽车充放电调度MATLAB程序

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 程序简介 该模型主要做的是基于拉格朗日分布算法的电动汽车充放电调度模型。利用蒙特卡洛模拟法模拟出电动汽车负荷曲线&#xff0c;并求解出无序充电功率曲线和有序充电曲线&#xff0c;该模型在电动汽车个…

【Linux 学习】进程优先级和命令行参数!

1. 什么是优先级? 指定进程获取某种资源&#xff08;CPU&#xff09;的先后顺序&#xff1b; Linux 中优先级数字越小&#xff0c;优先级越高&#xff1b; 1.1 优先级和权限的区别&#xff1f; 权限 &#xff1a; 能不能做 优先级&#xff1a; 已经能了&#xff0c;但是获…

RX8111CE支持电池供电设备实现多计算芯片的数据交互

随着电池技术的发展&#xff0c;其容量和质量得到了显著提高。在目前的电池供电设备中&#xff0c;常常也会将传统主处理器和协处理器的结构应用到其中&#xff0c;这种计算机结构的引入大幅度提高了电池供电设备的计算能力&#xff0c;但是对设计也提出了更高的要求。在时钟系…

【Linux】虚拟化技术docker搭建SuitoCRM系统及汉化

CRM系统 CRM&#xff08;Customer Relationship Management&#xff0c;客户关系管理&#xff09;系统是一种用于管理和优化企业与客户关系的软件工具。在商业竞争激烈的现代社会中&#xff0c;CRM系统已成为许多企业提高销售、增强客户满意度和实现持续增长的重要工具。 搭建…

FMEA风险分析中几个常用的模型——SunFMEA软件

FMEA风险分析是确保风险管理成效的重要环节之一。为了很好地实施风险分析&#xff0c;风险管理专家开发了许多模型帮助其顺利实施&#xff0c;这些模型包括&#xff1a;领结模型、风险指数模型、因果模型、安全栅分析模型等。今天SunFMEA软件系统和大家一起分享这几种常用得模型…

libVLC 提取视频帧使用QGraphicsView渲染

在前面章节中&#xff0c;我们讲解了如何使用QWidget渲染每一帧视频数据&#xff0c;这种方法对 CPU 负荷较高。 libVLC 提取视频帧使用QWidget渲染-CSDN博客 后面又讲解了使用OpenGL渲染每一帧视频数据&#xff0c;使用 OpenGL去绘制&#xff0c;利用 GPU 减轻 CPU 计算负荷…

【前端捉鬼记】使用nvm切换node版本后再用node -v查看仍然是原来的版本

今天遇到一个诡异的问题&#xff0c;使用nvm切换node版本&#xff0c;明明提示已经切换成功&#xff0c;可是再次查看node版本还是之前的&#xff01; 尝试了很多办法&#xff0c;比如重新打开一个cmd窗口、切换前执行nvm install version都没成功&#xff0c;直到找到这篇文章…

mapv修改源码实现图标和管道到统一页面显示,图标和管道和点击

一、效果图 二、背景 map 地图添加marker&#xff0c;是操作的dom&#xff0c;而mapv是使用的canvas方式&#xff0c;所以性能要好 三、Mapv和MapVGL的区别 百度地图 JavaScript API GL快速升级 和mapVGL的使用 Mapv 是一款基于百度地图的大数据可视化开源库&#xff0c;可以…