mysql面试题 二

超键、候选键、主键、外键分别是什么?

  • 超键:在关系中能唯一标识元组的属性集称为关系模式的超键。一个属性可以为作为一个超键,多个属性组合在一起也可以作为一个超键。超键包含候选键和主键。
  • 候选键:是最小超键,即没有冗余元素的超键。
  • 主键:数据库表中对储存数据对象予以唯一和完整标识的数据列或属性的组合。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(Null)。
  • 外键:在一个表中存在的另一个表的主键称此表的外键。

SQL 约束有哪几种?

SQL 约束有哪几种?

  • NOT NULL: 用于控制字段的内容一定不能为空(NULL)。
  • UNIQUE: 控件字段内容不能重复,一个表允许有多个 Unique 约束。
  • PRIMARY KEY: 也是用于控件字段内容不能重复,但它在一个表只允许出现一个。
  • FOREIGN KEY: 用于预防破坏表之间连接的动作,也能防止非法数据插入外键列,因为它必须是它指向的那个表中的值之一。
  • CHECK: 用于控制字段的值范围。

六种关联查询

  • 交叉连接(CROSS JOIN)

  • 内连接(INNER JOIN)

  • 外连接(LEFT JOIN/RIGHT JOIN)

  • 联合查询(UNION与UNION ALL)

  • 全连接(FULL JOIN)

  • 交叉连接(CROSS JOIN)

     

    复制代码

    SELECT * FROM A,B(,C)或者SELECT * FROM A CROSS JOIN B (CROSS JOIN C)#没有任何关联条件,结果是笛卡尔积,结果集会很大,没有意义,很少使用内连接(INNER JOIN)SELECT * FROM A,B WHERE A.id=B.id或者SELECT * FROM A INNER JOIN B ON A.id=B.id多表中同时符合某种条件的数据记录的集合,INNER JOIN可以缩写为JOIN

内连接分为三类

  • 等值连接:ON A.id=B.id
  • 不等值连接:ON A.id > B.id
  • 自连接:SELECT * FROM A T1 INNER JOIN A T2 ON T1.id=T2.pid

外连接(LEFT JOIN/RIGHT JOIN)

  • 左外连接:LEFT OUTER JOIN, 以左表为主,先查询出左表,按照ON后的关联条件匹配右表,没有匹配到的用NULL填充,可以简写成LEFT JOIN
  • 右外连接:RIGHT OUTER JOIN, 以右表为主,先查询出右表,按照ON后的关联条件匹配左表,没有匹配到的用NULL填充,可以简写成RIGHT JOIN

联合查询(UNION与UNION ALL)

 

n1ql

复制代码

SELECT * FROM A UNION SELECT * FROM B UNION ...

  • 就是把多个结果集集中在一起,UNION前的结果为基准,需要注意的是联合查询的列数要相等,相同的记录行会合并
  • 如果使用UNION ALL,不会合并重复的记录行
  • 效率 UNION 高于 UNION ALL

全连接(FULL JOIN)

 

复制代码

SELECT * FROM A LEFT JOIN B ON A.id=B.id UNIONSELECT * FROM A RIGHT JOIN B ON A.id=B.id

  • MySQL不支持全连接
  • 可以使用LEFT JOIN 和UNION和RIGHT JOIN联合使用
表连接面试题
有2张表。
  • 1张R、1张S,R表有ABC三列,S表有CD两列,表中各有三条记录

R表

ABC
a1b1c1
a2b2c2
a3b3c3

S表

CD
c1d1
c2d2
c4d3
1、交叉连接(笛卡尔积)
  • SQL
 

复制代码

select r.*,s.* from r,s

  • 结果
ABCCD
a1b1c1c1d1
a2b2c2c1d1
a3b3c3c1d1
a1b1c1c2d2
a2b2c2c2d2
a3b3c3c2d2
a1b1c1c4d3
a2b2c2c4d3
a3b3c3c4d3
2、内连接结果
  • SQL
 

复制代码

select r.*,s.* from r inner join s on r.c=s.c

  • 结果
ABCCD
a1b1c1c1d1
a2b2c2c2d2
3、左连接结果
  • SQL
 

复制代码

select r.*,s.* from r left join s on r.c=s.c

  • 结果
ABCCD
a1b1c1c1d1
a2b2c2c2d2
a3b3c3
4、右连接结果
  • SQL
 

复制代码

select r.*,s.* from r right join s on r.c=s.c

  • 结果
ABCCD
a1b1c1c1d1
a2b2c2c2d2
c4d3
5、全表连接的结果(MySql不支持,Oracle支持)
  • SQL
 

复制代码

select r.*,s.* from r full join s on r.c=s.c

  • 结果
ABCCD
a1b1c1c1d1
a2b2c2c2d2
a3b3c3
c4d3

什么是子查询

  1. 条件:一条SQL语句的查询结果做为另一条查询语句的条件或查询结果

  2. 嵌套:多条SQL语句嵌套使用,内部的SQL查询语句称为子查询。

mysql中 in 和 exists 区别

  • mysql中的in语句是把外表和内表作hash 连接,而exists语句是对外表作loop循环,每次loop循环再对内表进行查询。一直大家都认为exists比in语句的效率要高,这种说法其实是不准确的。这个是要区分环境的。
    1. 如果查询的两个表大小相当,那么用in和exists差别不大。
    2. 如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in。
    3. not in 和not exists:如果查询语句使用了not in,那么内外表都进行全表扫描,没有用到索引;而not extsts的子查询依然能用到表上的索引。所以无论那个表大,用not exists都比not in要快。

varchar与char的区别

char的特点

  • char表示定长字符串,长度是固定的;

  • 如果插入数据的长度小于char的固定长度时,则用空格填充;

  • 因为长度固定,所以存取速度要比varchar快很多,甚至能快50%,但正因为其长度固定,所以会占据多余的空间,是空间换时间的做法;

  • 对于char来说,最多能存放的字符个数为255,和编码无关

varchar的特点

  • varchar表示可变长字符串,长度是可变的;

  • 插入的数据是多长,就按照多长来存储;

  • varchar在存取方面与char相反,它存取慢,因为长度不固定,但正因如此,不占据多余的空间,是时间换空间的做法;

  • 对于varchar来说,最多能存放的字符个数为65532

总之,结合性能角度(char更快)和节省磁盘空间角度(varchar更小),具体情况还需具体来设计数据库才是妥当的做法。

varchar(50)中50的涵义

  • 最多存放50个字符,varchar(50)和(200)存储hello所占空间一样,但后者在排序时会消耗更多内存,因为order by col采用fixed_length计算col长度(memory引擎也一样)。在早期 MySQL 版本中, 50 代表字节数,现在代表字符数。

int(20)中20的涵义

  • 是指显示字符的长度。20表示最大显示宽度为20,但仍占4字节存储,存储范围不变;

  • 不影响内部存储,只是影响带 zerofill 定义的 int 时,前面补多少个 0,易于报表展示

mysql为什么这么设计

  • 对大多数应用没有意义,只是规定一些工具用来显示字符的个数;int(1)和int(20)存储和计算均一样;

mysql中int(10)和char(10)以及varchar(10)的区别

  • int(10)的10表示显示的数据的长度,不是存储数据的大小;chart(10)和varchar(10)的10表示存储数据的大小,即表示存储多少个字符。

  • char(10)表示存储定长的10个字符,不足10个就用空格补齐,占用更多的存储空间

  • varchar(10)表示存储10个变长的字符,存储多少个就是多少个,空格也按一个字符存储,这一点是和char(10)的空格不同的,char(10)的空格表示占位不算一个字符

FLOAT和DOUBLE的区别是什么?

  • FLOAT类型数据可以存储至多8位十进制数,并在内存中占4字节。
  • DOUBLE类型数据可以存储至多18位十进制数,并在内存中占8字节。

drop、delete与truncate的区别

  • 三者都表示删除,但是三者有一些差别:
比较DeleteTruncateDrop
类型属于DML属于DDL属于DDL
回滚可回滚不可回滚不可回滚
删除内容表结构还在,删除表的全部或者一部分数据行表结构还在,删除表中的所有数据从数据库中删除表,所有的数据行,索引和权限也会被删除
删除速度删除速度慢,需要逐行删除删除速度快删除速度最快
  • 因此,在不再需要一张表的时候,用drop;在想删除部分数据行时候,用delete;在保留表而删除所有数据的时候用truncate。

UNION与UNION ALL的区别?

  • 如果使用UNION ALL,不会合并重复的记录行
  • 效率 UNION 高于 UNION ALL

SQL优化

说出一些数据库优化方面的经验?

  1. 有外键约束的话会影响增删改的性能,如果应用程序可以保证数据库的完整性那就去除外键
  2. Sql语句全部大写,特别是列名大写,因为数据库的机制是这样的,sql语句发送到数据库服务器,数据库首先就会把sql编译成大写在执行,如果一开始就编译成大写就不需要了把sql编译成大写这个步骤了
  3. 如果应用程序可以保证数据库的完整性,可以不需要按照三大范式来设计数据库
  4. 其实可以不必要创建很多索引,索引可以加快查询速度,但是索引会消耗磁盘空间
  5. 如果是jdbc的话,使用PreparedStatement不使用Statement,来创建SQl,PreparedStatement的性能比Statement的速度要快,使用PreparedStatement对象SQL语句会预编译在此对象中,PreparedStatement对象可以多次高效的执行

怎么优化SQL查询语句吗

  1. 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引
  2. 用索引可以提高查询
  3. SELECT子句中避免使用*号,尽量全部大写SQL
  4. 应尽量避免在 where 子句中对字段进行 is null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,使用 IS NOT NULL
  5. where 子句中使用 or 来连接条件,也会导致引擎放弃使用索引而进行全表扫描
  6. in 和 not in 也要慎用,否则会导致全表扫描

你怎么知道SQL语句性能是高还是低

  1. 查看SQL的执行时间
  2. 使用explain关键字可以模拟优化器执行SQL查询语句,从而知道MYSQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈。

SQL的执行顺序

  1. FROM:将数据从硬盘加载到数据缓冲区,方便对接下来的数据进行操作。
  2. WHERE:从基表或视图中选择满足条件的元组。(不能使用聚合函数)
  3. JOIN(如right left 右连接-------从右边表中读取某个元组,并且找到该元组在左边表中对应的元组或元组集)
  4. ON:join on实现多表连接查询,推荐该种方式进行多表查询,不使用子查询。
  5. GROUP BY:分组,一般和聚合函数一起使用。
  6. HAVING:在元组的基础上进行筛选,选出符合条件的元组。(一般与GROUP BY进行连用)
  7. SELECT:查询到得所有元组需要罗列的哪些列。
  8. DISTINCT:去重的功能。
  9. UNION:将多个查询结果合并(默认去掉重复的记录)。
  10. ORDER BY:进行相应的排序。
  11. LIMIT 1:显示输出一条数据记录(元组)

如何定位及优化SQL语句的性能问题?创建的索引有没有被使用到?或者说怎么才可以知道这条语句运行很慢的原因?

  • 对于低性能的SQL语句的定位,最重要也是最有效的方法就是使用执行计划,MySQL提供了explain命令来查看语句的执行计划。 我们知道,不管是哪种数据库,或者是哪种数据库引擎,在对一条SQL语句进行执行的过程中都会做很多相关的优化,对于查询语句,最重要的优化方式就是使用索引。 而执行计划,就是显示数据库引擎对于SQL语句的执行的详细情况,其中包含了是否使用索引,使用什么索引,使用的索引的相关信息等

在这里插入图片描述

 

  • 执行计划包含的信息 id 有一组数字组成。表示一个查询中各个子查询的执行顺序;
    • id相同执行顺序由上至下。
    • id不同,id值越大优先级越高,越先被执行。
    • id为null时表示一个结果集,不需要使用它查询,常出现在包含union等查询语句中。

select_type 每个子查询的查询类型,一些常见的查询类型。

idselect_typedescription
1SIMPLE不包含任何子查询或union等查询
2PRIMARY包含子查询最外层查询就显示为 PRIMARY
3SUBQUERY在select或 where字句中包含的查询
4DERIVEDfrom字句中包含的查询
5UNION出现在union后的查询语句中
6UNION RESULT从UNION中获取结果集,例如上文的第三个例子
  • table 查询的数据表,当从衍生表中查数据时会显示 x 表示对应的执行计划id partitions 表分区、表创建的时候可以指定通过那个列进行表分区。 举个例子:
 

复制代码

create table tmp ( id int unsigned not null AUTO_INCREMENT, name varchar(255), PRIMARY KEY (id) ) engine = innodb partition by key (id) partitions 5;

  • type(非常重要,可以看到有没有走索引) 访问类型

    • ALL 扫描全表数据
    • index 遍历索引
    • range 索引范围查找
    • index_subquery 在子查询中使用 ref
    • unique_subquery 在子查询中使用 eq_ref
    • ref_or_null 对Null进行索引的优化的 ref
    • fulltext 使用全文索引
    • ref 使用非唯一索引查找数据
    • eq_ref 在join查询中使用PRIMARY KEYorUNIQUE NOT NULL索引关联。
  • possible_keys 可能使用的索引,注意不一定会使用。查询涉及到的字段上若存在索引,则该索引将被列出来。当该列为 NULL时就要考虑当前的SQL是否需要优化了。

  • key 显示MySQL在查询中实际使用的索引,若没有使用索引,显示为NULL。

  • TIPS:查询中若使用了覆盖索引(覆盖索引:索引的数据覆盖了需要查询的所有数据),则该索引仅出现在key列表中

  • key_length 索引长度

  • ref 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

  • rows 返回估算的结果集数目,并不是一个准确的值。

  • extra 的信息非常丰富,常见的有:

    1. Using index 使用覆盖索引
    2. Using where 使用了用where子句来过滤结果集
    3. Using filesort 使用文件排序,使用非索引列进行排序时出现,非常消耗性能,尽量优化。
    4. Using temporary 使用了临时表 sql优化的目标可以参考阿里开发手册
 

复制代码

【推荐】SQL性能优化的目标:至少要达到 range 级别,要求是ref级别,如果可以是consts最好。 说明: 1) consts 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。 2) ref 指的是使用普通的索引(normal index)。 3) range 对索引进行范围检索。 反例:explain表的结果,type=index,索引物理文件全扫描,速度非常慢,这个index级别比较range还低,与全表扫描是小巫见大巫。

SQL的生命周期?

  1. 应用服务器与数据库服务器建立一个连接

  2. 数据库进程拿到请求sql

  3. 解析并生成执行计划,执行

  4. 读取数据到内存并进行逻辑处理

  5. 通过步骤一的连接,发送结果到客户端

  6. 关掉连接,释放资源

在这里插入图片描述

 

大表数据查询,怎么优化

  1. 优化shema、sql语句+索引;
  2. 第二加缓存,memcached, redis;
  3. 主从复制,读写分离;
  4. 垂直拆分,根据你模块的耦合度,将一个大的系统分为多个小的系统,也就是分布式系统;
  5. 水平切分,针对数据量大的表,这一步最麻烦,最能考验技术水平,要选择一个合理的sharding key, 为了有好的查询效率,表结构也要改动,做一定的冗余,应用也要改,sql中尽量带sharding key,将数据定位到限定的表上去查,而不是扫描全部的表;

超大分页怎么处理?

超大的分页一般从两个方向上来解决.

  • 数据库层面,这也是我们主要集中关注的(虽然收效没那么大),类似于select * from table where age > 20 limit 1000000,10这种查询其实也是有可以优化的余地的. 这条语句需要load1000000数据然后基本上全部丢弃,只取10条当然比较慢. 当时我们可以修改为select * from table where id in (select id from table where age > 20 limit 1000000,10).这样虽然也load了一百万的数据,但是由于索引覆盖,要查询的所有字段都在索引中,所以速度会很快. 同时如果ID连续的好,我们还可以select * from table where id > 1000000 limit 10,效率也是不错的,优化的可能性有许多种,但是核心思想都一样,就是减少load的数据.
  • 从需求的角度减少这种请求…主要是不做类似的需求(直接跳转到几百万页之后的具体某一页.只允许逐页查看或者按照给定的路线走,这样可预测,可缓存)以及防止ID泄漏且连续被人恶意攻击.

解决超大分页,其实主要是靠缓存,可预测性的提前查到内容,缓存至redis等k-V数据库中,直接返回即可

mysql 分页

  • LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数。LIMIT 接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初始记录行的偏移量是 0(而不是 1)

    SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15

  • 为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1:

    SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last.

  • 如果只给定一个参数,它表示返回最大的记录行数目:

    SELECT * FROM table LIMIT 5; //检索前 5 个记录行

  • 换句话说,LIMIT n 等价于 LIMIT 0,n。

慢查询日志

用于记录执行时间超过某个临界值的SQL日志,用于快速定位慢查询,为我们的优化做参考。

  • 开启慢查询日志

  • 配置项:slow_query_log

  • 可以使用show variables like ‘slov_query_log’查看是否开启,如果状态值为OFF,可以使用set GLOBAL slow_query_log = on来开启,它会在datadir下产生一个xxx-slow.log的文件。

  • 设置临界时间

  • 配置项:long_query_time

  • 查看:show VARIABLES like 'long_query_time',单位秒

  • 设置:set long_query_time=0.5

  • 实操时应该从长时间设置到短的时间,即将最慢的SQL优化掉

  • 查看日志,一旦SQL超过了我们设置的临界时间就会被记录到xxx-slow.log

关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过?

  • 在业务系统中,除了使用主键进行的查询,其他的我都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会定期将业务中的慢查询反馈给我们。

  • 慢查询的优化首先要搞明白慢的原因是什么? 是查询条件没有命中索引?是load了不需要的数据列?还是数据量太大?

所以优化也是针对这三个方向来的,

  • 首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写。
  • 分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引。
  • 如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表。

为什么要尽量设定一个主键?

  • 主键是数据库确保数据行在整张表唯一性的保障,即使业务上本张表没有主键,也建议添加一个自增长的ID列作为主键。设定了主键之后,在后续的删改查的时候可能更加快速以及确保操作数据范围安全。

主键使用自增ID还是UUID?

  • 推荐使用自增ID,不要使用UUID。

  • 因为在InnoDB存储引擎中,主键索引是作为聚簇索引存在的,也就是说,主键索引的B+树叶子节点上存储了主键索引以及全部的数据(按照顺序),如果主键索引是自增ID,那么只需要不断向后排列即可,如果是UUID,由于到来的ID与原来的大小不确定,会造成非常多的数据插入,数据移动,然后导致产生很多的内存碎片,进而造成插入性能的下降。

总之,在数据量大一些的情况下,用自增主键性能会好一些。

关于主键是聚簇索引,如果没有主键,InnoDB会选择一个唯一键来作为聚簇索引,如果没有唯一键,会生成一个隐式的主键。

字段为什么要求定义为not null?

  • null值会占用更多的字节,且会在程序中造成很多与预期不符的情况。

如果要存储用户的密码散列,应该使用什么字段进行存储?

  • 密码散列,盐,用户身份证号等固定长度的字符串应该使用char而不是varchar来存储,这样可以节省空间且提高检索效率。

如何优化查询过程中的数据访问

  • 访问数据太多导致查询性能下降
  • 确定应用程序是否在检索大量超过需要的数据,可能是太多行或列
  • 确认MySQL服务器是否在分析大量不必要的数据行
  • 避免犯如下SQL语句错误
  • 避免查询不需要的数据。解决办法:使用limit解决
  • 多表关联返回全部列。解决办法:指定列名
  • 总是返回全部列。解决办法:避免使用SELECT *
  • 重复查询相同的数据。解决办法:可以缓存数据,下次直接读取缓存
  • 使用explain进行分析,如果发现查询需要扫描大量的数据,但只返回少数的行,可以通过如下技巧去优化:
  • 使用索引覆盖扫描,把所有的列都放到索引中,这样存储引擎不需要回表获取对应行就可以返回结果。
  • 改变数据库和表的结构,修改数据表范式
  • 重写SQL语句,让优化器可以以更优的方式执行查询。

如何优化长难的查询语句

  • 分析是一个复杂查询还是多个简单查询速度快
  • MySQL内部每秒能扫描内存中上百万行数据,相比之下,响应数据给客户端就要慢得多
  • 使用尽可能小的查询是好的,但是有时将一个大的查询分解为多个小的查询是很有必要的。
  • 将一个大的查询分为多个小的相同的查询
  • 一次性删除1000万的数据要比一次删除1万,暂停一会的方案更加损耗服务器开销。
  • 分解关联查询,让缓存的效率更高。
  • 执行单个查询可以减少锁的竞争。
  • 在应用层做关联更容易对数据库进行拆分。
  • 查询效率会有大幅提升。
  • 较少冗余记录的查询。

优化特定类型的查询语句

  • count(*)会忽略所有的列,直接统计所有列数,不要使用count(列名)
  • MyISAM中,没有任何where条件的count(*)非常快。
  • 当有where条件时,MyISAM的count统计不一定比其它引擎快。
  • 可以使用explain查询近似值,用近似值替代count(*)
  • 增加汇总表
  • 使用缓存

优化关联查询

  • 确定ON或者USING子句中是否有索引。
  • 确保GROUP BY和ORDER BY只有一个表中的列,这样MySQL才有可能使用索引。

优化子查询

  • 用关联查询替代
  • 优化GROUP BY和DISTINCT
  • 这两种查询据可以使用索引来优化,是最有效的优化方法
  • 关联查询中,使用标识列分组的效率更高
  • 如果不需要ORDER BY,进行GROUP BY时加ORDER BY NULL,MySQL不会再进行文件排序。
  • WITH ROLLUP超级聚合,可以挪到应用程序处理

优化LIMIT分页

  • LIMIT偏移量大的时候,查询效率较低
  • 可以记录上次查询的最大ID,下次查询时直接根据该ID来查询

优化UNION查询

  • UNION ALL的效率高于UNION

优化WHERE子句

  • 多数数据库都是从左往右的顺序处理条件的,把能够过滤更多数据的条件放到前面,把过滤少的条件放在后面

SQL语句优化的一些方法

  • 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

  • 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:

     

    复制代码

    select id from t where num is null -- 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: select id from t where num=0
  • 3.应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。

  • 4.应尽量避免在 where 子句中使用or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:

     

    复制代码

    select id from t where num=10 or num=20 -- 可以这样查询: select id from t where num=10 union all select id from t where num=20
  • 5.in 和 not in 也要慎用,否则会导致全表扫描,如:

     

    复制代码

    select id from t where num in(1,2,3) -- 对于连续的数值,能用 between 就不要用 in 了: select id from t where num between 1 and 3
  • 6.下面的查询也将导致全表扫描:select id from t where name like ‘%李%’若要提高效率,可以考虑全文检索。

  • 7.如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然 而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:

     

    复制代码

    select id from t where num=@num -- 可以改为强制查询使用索引: select id from t with(index(索引名)) where num=@num
  • 8.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:

     

    复制代码

    select id from t where num/2=100 -- 应改为: select id from t where num=100*2
  • 9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:

     

    复制代码

    select id from t where substring(name,1,3)=’abc’ -- name以abc开头的id应改为: select id from t where name like ‘abc%’
  • 10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

数据库优化

为什么要优化

  • 系统的吞吐量瓶颈往往出现在数据库的访问速度上
  • 随着应用程序的运行,数据库的中的数据会越来越多,处理时间会相应变慢
  • 数据是存放在磁盘上的,读写速度无法和内存相比

优化原则:减少系统瓶颈,减少资源占用,增加系统的反应速度。

数据库结构优化

  • 一个好的数据库设计方案对于数据库的性能往往会起到事半功倍的效果。

  • 需要考虑数据冗余、查询和更新的速度、字段的数据类型是否合理等多方面的内容。

将字段很多的表分解成多个表

  • 对于字段较多的表,如果有些字段的使用频率很低,可以将这些字段分离出来形成新表。

  • 因为当一个表的数据量很大时,会由于使用频率低的字段的存在而变慢。

增加中间表

  • 对于需要经常联合查询的表,可以建立中间表以提高查询效率。

  • 通过建立中间表,将需要通过联合查询的数据插入到中间表中,然后将原来的联合查询改为对中间表的查询。

增加冗余字段

  • 设计数据表时应尽量遵循范式理论的规约,尽可能的减少冗余字段,让数据库设计看起来精致、优雅。但是,合理的加入冗余字段可以提高查询速度。

  • 表的规范化程度越高,表和表之间的关系越多,需要连接查询的情况也就越多,性能也就越差。

注意:

冗余字段的值在一个表中修改了,就要想办法在其他表中更新,否则就会导致数据不一致的问题。

MySQL数据库cpu飙升到500%的话他怎么处理?

  • 当 cpu 飙升到 500%时,先用操作系统命令 top 命令观察是不是 mysqld 占用导致的,如果不是,找出占用高的进程,并进行相关处理。

  • 如果是 mysqld 造成的, show processlist,看看里面跑的 session 情况,是不是有消耗资源的 sql 在运行。找出消耗高的 sql,看看执行计划是否准确, index 是否缺失,或者实在是数据量太大造成。

  • 一般来说,肯定要 kill 掉这些线程(同时观察 cpu 使用率是否下降),等进行相应的调整(比如说加索引、改 sql、改内存参数)之后,再重新跑这些 SQL。

  • 也有可能是每个 sql 消耗资源并不多,但是突然之间,有大量的 session 连进来导致 cpu 飙升,这种情况就需要跟应用一起来分析为何连接数会激增,再做出相应的调整,比如说限制连接数等

大表怎么优化?分库分表了是怎么做的?分表分库了有什么问题?有用到中间件么?他们的原理知道么?

当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下:

  1. 限定数据的范围: 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内。;
  2. 读/写分离: 经典的数据库拆分方案,主库负责写,从库负责读;
  3. 缓存: 使用MySQL的缓存,另外对重量级、更新少的数据可以考虑使用应用级别的缓存;

还有就是通过分库分表的方式进行优化,主要有垂直分区、垂直分表和水平分区、水平分表

1、垂直分区
  • 根据数据库里面数据表的相关性进行拆分。 例如,用户表中既有用户的登录信息又有用户的基本信息,可以将用户表拆分成两个单独的表,甚至放到单独的库做分库。

  • 简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。 如下图所示,这样来说大家应该就更容易理解了。

在这里插入图片描述

 

  • 垂直拆分的优点: 可以使得行数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。

  • 垂直拆分的缺点: 主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决。此外,垂直分区会让事务变得更加复杂;

2、垂直分表
  • 把主键和一些列放在一个表,然后把主键和另外的列放在另一个表中

在这里插入图片描述

 

适用场景

  • 1、如果一个表中某些列常用,另外一些列不常用
  • 2、可以使数据行变小,一个数据页能存储更多数据,查询时减少I/O次数

缺点

  • 有些分表的策略基于应用层的逻辑算法,一旦逻辑算法改变,整个分表逻辑都会改变,扩展性较差
  • 对于应用层来说,逻辑算法增加开发成本
  • 管理冗余列,查询所有数据需要join操作
3、水平分区
  • 保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。 水平拆分可以支撑非常大的数据量。

  • 水平拆分是指数据表行的拆分,表的行数超过200万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放。举个例子:我们可以将用户信息表拆分成多个用户信息表,这样就可以避免单一表数据量过大对性能造成影响。

在这里插入图片描述

 

  • 水品拆分可以支持非常大的数据量。需要注意的一点是:分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义,所以 水平拆分最好分库

  • 水平拆分能够 支持非常大的数据量存储,应用端改造也少,但 分片事务难以解决 ,跨界点Join性能较差,逻辑复杂。

《Java工程师修炼之道》的作者推荐 尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度 ,一般的数据表在优化得当的情况下支撑千万以下的数据量是没有太大问题的。如果实在要分片,尽量选择客户端分片架构,这样可以减少一次和中间件的网络I/O。

4、水平分表:
  • 表很大,分割后可以降低在查询时需要读的数据和索引的页数,同时也降低了索引的层数,提高查询次数

在这里插入图片描述

 

适用场景

  • 1、表中的数据本身就有独立性,例如表中分表记录各个地区的数据或者不同时期的数据,特别是有些数据常用,有些不常用。
  • 2、需要把数据存放在多个介质上。

水平切分的缺点

  • 1、给应用增加复杂度,通常查询时需要多个表名,查询所有数据都需UNION操作
  • 2、在许多数据库应用中,这种复杂度会超过它带来的优点,查询时会增加读一个索引层的磁盘次数
数据库分片的两种常见方案:
  • 客户端代理: 分片逻辑在应用端,封装在jar包中,通过修改或者封装JDBC层来实现。 当当网的 Sharding-JDBC 、阿里的TDDL是两种比较常用的实现。
  • 中间件代理: 在应用和数据中间加了一个代理层。分片逻辑统一维护在中间件服务中。 我们现在谈的 Mycat 、360的Atlas、网易的DDB等等都是这种架构的实现。
分库分表后面临的问题
  • 事务支持 分库分表后,就成了分布式事务了。如果依赖数据库本身的分布式事务管理功能去执行事务,将付出高昂的性能代价; 如果由应用程序去协助控制,形成程序逻辑上的事务,又会造成编程方面的负担。

  • 跨库join

    只要是进行切分,跨节点Join的问题是不可避免的。但是良好的设计和切分却可以减少此类情况的发生。解决这一问题的普遍做法是分两次查询实现。在第一次查询的结果集中找出关联数据的id,根据这些id发起第二次请求得到关联数据。 分库分表方案产品

  • 跨节点的count,order by,group by以及聚合函数问题 这些是一类问题,因为它们都需要基于全部数据集合进行计算。多数的代理都不会自动处理合并工作。解决方案:与解决跨节点join问题的类似,分别在各个节点上得到结果后在应用程序端进行合并。和join不同的是每个结点的查询可以并行执行,因此很多时候它的速度要比单一大表快很多。但如果结果集很大,对应用程序内存的消耗是一个问题。

  • 数据迁移,容量规划,扩容等问题 来自淘宝综合业务平台团队,它利用对2的倍数取余具有向前兼容的特性(如对4取余得1的数对2取余也是1)来分配数据,避免了行级别的数据迁移,但是依然需要进行表级别的迁移,同时对扩容规模和分表数量都有限制。总得来说,这些方案都不是十分的理想,多多少少都存在一些缺点,这也从一个侧面反映出了Sharding扩容的难度。

  • ID问题

  • 一旦数据库被切分到多个物理结点上,我们将不能再依赖数据库自身的主键生成机制。一方面,某个分区数据库自生成的ID无法保证在全局上是唯一的;另一方面,应用程序在插入数据之前需要先获得ID,以便进行SQL路由. 一些常见的主键生成策略

    • UUID 使用UUID作主键是最简单的方案,但是缺点也是非常明显的。由于UUID非常的长,除占用大量存储空间外,最主要的问题是在索引上,在建立索引和基于索引进行查询时都存在性能问题。 Twitter的分布式自增ID算法Snowflake 在分布式系统中,需要生成全局UID的场合还是比较多的,twitter的snowflake解决了这种需求,实现也还是很简单的,除去配置信息,核心代码就是毫秒级时间41位 机器ID 10位 毫秒内序列12位。
  • 跨分片的排序分页问题

    一般来讲,分页时需要按照指定字段进行排序。当排序字段就是分片字段的时候,我们通过分片规则可以比较容易定位到指定的分片,而当排序字段非分片字段的时候,情况就会变得比较复杂了。为了最终结果的准确性,我们需要在不同的分片节点中将数据进行排序并返回,并将不同分片返回的结果集进行汇总和再次排序,最后再返回给用户。如下图所示:

    在这里插入图片描述

MySQL的复制原理以及流程

  • 主从复制:将主数据库中的DDL和DML操作通过二进制日志(BINLOG)传输到从数据库上,然后将这些日志重新执行(重做);从而使得从数据库的数据与主数据库保持一致。
主从复制的作用
  1. 主数据库出现问题,可以切换到从数据库。
  2. 可以进行数据库层面的读写分离。
  3. 可以在从数据库上进行日常备份。
MySQL主从复制解决的问题
  • 数据分布:随意开始或停止复制,并在不同地理位置分布数据备份
  • 负载均衡:降低单个服务器的压力
  • 高可用和故障切换:帮助应用程序避免单点失败
  • 升级测试:可以用更高版本的MySQL作为从库
MySQL主从复制工作原理
  • 在主库上把数据更高记录到二进制日志
  • 从库将主库的日志复制到自己的中继日志
  • 从库读取中继日志的事件,将其重放到从库数据中
基本原理流程,3个线程以及之间的关联
  • :binlog线程——记录下所有改变了数据库数据的语句,放进master上的binlog中;

  • :io线程——在使用start slave 之后,负责从master上拉取 binlog 内容,放进自己的relay log中;

  • :sql执行线程——执行relay log中的语句;

复制过程

在这里插入图片描述

 

  • Binary log:主数据库的二进制日志

  • Relay log:从服务器的中继日志

  1. master在每个事务更新数据完成之前,将该操作记录串行地写入到binlog文件中。
  2. salve开启一个I/O Thread,该线程在master打开一个普通连接,主要工作是binlog dump process。如果读取的进度已经跟上了master,就进入睡眠状态并等待master产生新的事件。I/O线程最终的目的是将这些事件写入到中继日志中。
  3. SQL Thread会读取中继日志,并顺序执行该日志中的SQL事件,从而与主数据库中的数据保持一致。

读写分离有哪些解决方案?

  • 读写分离是依赖于主从复制,而主从复制又是为读写分离服务的。因为主从复制要求slave不能写只能读(如果对slave执行写操作,那么show slave status将会呈现Slave_SQL_Running=NO,此时你需要按照前面提到的手动同步一下slave)。

方案一

  • 使用mysql-proxy代理

  • 优点:直接实现读写分离和负载均衡,不用修改代码,master和slave用一样的帐号,mysql官方不建议实际生产中使用

  • 缺点:降低性能, 不支持事务

方案二

  • 使用AbstractRoutingDataSource+aop+annotation在dao层决定数据源。
  • 如果采用了mybatis, 可以将读写分离放在ORM层,比如mybatis可以通过mybatis plugin拦截sql语句,所有的insert/update/delete都访问master库,所有的select 都访问salve库,这样对于dao层都是透明。 plugin实现时可以通过注解或者分析语句是读写方法来选定主从库。不过这样依然有一个问题, 也就是不支持事务, 所以我们还需要重写一下DataSourceTransactionManager, 将read-only的事务扔进读库, 其余的有读有写的扔进写库。

方案三

  • 使用AbstractRoutingDataSource+aop+annotation在service层决定数据源,可以支持事务.

  • 缺点:类内部方法通过this.xx()方式相互调用时,aop不会进行拦截,需进行特殊处理。

备份计划,mysqldump以及xtranbackup的实现原理

  • (1)备份计划

    • 视库的大小来定,一般来说 100G 内的库,可以考虑使用 mysqldump 来做,因为 mysqldump更加轻巧灵活,备份时间选在业务低峰期,可以每天进行都进行全量备份(mysqldump 备份出来的文件比较小,压缩之后更小)。

    • 100G 以上的库,可以考虑用 xtranbackup 来做,备份速度明显要比 mysqldump 要快。一般是选择一周一个全备,其余每天进行增量备份,备份时间为业务低峰期。

  • (2)备份恢复时间

    • 物理备份恢复快,逻辑备份恢复慢

    • 这里跟机器,尤其是硬盘的速率有关系,以下列举几个仅供参考

    • 20G的2分钟(mysqldump)

    • 80G的30分钟(mysqldump)

    • 111G的30分钟(mysqldump)

    • 288G的3小时(xtra)

    • 3T的4小时(xtra)

    • 逻辑导入时间一般是备份时间的5倍以上

  • (3)备份恢复失败如何处理

    • 首先在恢复之前就应该做足准备工作,避免恢复的时候出错。比如说备份之后的有效性检查、权限检查、空间检查等。如果万一报错,再根据报错的提示来进行相应的调整。

(4)mysqldump和xtrabackup实现原理

  • mysqldump

    mysqldump 属于逻辑备份。加入–single-transaction 选项可以进行一致性备份。后台进程会先设置 session 的事务隔离级别为 RR(SET SESSION TRANSACTION ISOLATION LEVELREPEATABLE READ),之后显式开启一个事务(START TRANSACTION /*!40100 WITH CONSISTENTSNAPSHOT */),这样就保证了该事务里读到的数据都是事务事务时候的快照。之后再把表的数据读取出来。如果加上–master-data=1 的话,在刚开始的时候还会加一个数据库的读锁(FLUSH TABLES WITH READ LOCK),等开启事务后,再记录下数据库此时 binlog 的位置(showmaster status),马上解锁,再读取表的数据。等所有的数据都已经导完,就可以结束事务

  • Xtrabackup:

    xtrabackup 属于物理备份,直接拷贝表空间文件,同时不断扫描产生的 redo 日志并保存下来。最后完成 innodb 的备份后,会做一个 flush engine logs 的操作(老版本在有 bug,在5.6 上不做此操作会丢数据),确保所有的 redo log 都已经落盘(涉及到事务的两阶段提交

  • 概念,因为 xtrabackup 并不拷贝 binlog,所以必须保证所有的 redo log 都落盘,否则可能会丢最后一组提交事务的数据)。这个时间点就是 innodb 完成备份的时间点,数据文件虽然不是一致性的,但是有这段时间的 redo 就可以让数据文件达到一致性(恢复的时候做的事情)。然后还需要 flush tables with read lock,把 myisam 等其他引擎的表给备份出来,备份完后解锁。这样就做到了完美的热备。

数据表损坏的修复方式有哪些?

使用 myisamchk 来修复,具体步骤:

  • 1 修复前将mysql服务停止。
  • 2 打开命令行方式,然后进入到mysql的/bin目录。
  • 3 执行myisamchk –recover 数据库所在路径/*.MYI

使用repair table 或者 OPTIMIZE table命令来修复,REPAIR TABLE table\_name 修复表 OPTIMIZE TABLE table\_name 优化表 REPAIR TABLE 用于修复被破坏的表。 OPTIMIZE TABLE 用于回收闲置的数据库空间,当表上的数据行被删除时,所占据的磁盘空间并没有立即被回收,使用了OPTIMIZE TABLE命令后这些空间将被回收,并且对磁盘上的数据行进行重排(注意:是磁盘上,而非数据库)

作者:小杰要吃蛋
链接:https://juejin.cn/post/6844904127047139335
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

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

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

相关文章

【Altium Designer 20 笔记】PCB板框

Altium Designer中设置PCB板框 PCB板框位于Mechanical1层 点击放置中的线条或使用其他绘图工具来绘制板框, 可以绘制矩形、圆形或其他形状的板框,确保板框是闭合的 注意&#xff1a;在绘制板框时&#xff0c;确保线条的起点和终点相连&#xff0c;形成一个闭合的图形。 快捷键D…

【C++航海王:追寻罗杰的编程之路】异常——错误处理方式之一

目录 引言 1 -> C语言传统的处理错误的方式 2 -> C异常概念 3 -> 异常的使用 3.1 -> 异常的抛出和捕获 3.2 -> 异常的重新抛出 3.3 -> 异常规范 4 -> 自定义异常体系 5 -> C标准库的异常体系 6 -> 异常的优缺点 引言 在C编程中&#xff…

C++ | Leetcode C++题解之第32题最长有效括号

题目&#xff1a; 题解&#xff1a; class Solution { public:int longestValidParentheses(string s) {int left 0, right 0, maxlength 0;for (int i 0; i < s.length(); i) {if (s[i] () {left;} else {right;}if (left right) {maxlength max(maxlength, 2 * ri…

单细胞分析|映射和注释查询数据集

reference映射简介 在本文中&#xff0c;我们首先构建一个reference&#xff0c;然后演示如何利用该reference来注释新的查询数据集。生成后&#xff0c;该reference可用于通过cell类型标签传输和将查询cell投影到reference UMAP 等任务来分析其他查询数据集。值得注意的是&am…

做一个好的程序员难吗?只需要这10个习惯

在这个世界上&#xff0c;有数以百万计的人对软件开发充满热情&#xff0c;他们有很多名字&#xff0c;如软件工程师、程序员、编码员、开发人员。一段时间后&#xff0c;这些人可能会成为一名优秀的编码员&#xff0c;并且他们将非常熟悉如何使用计算机语言完成工作。但是&…

【LeetCode】 2724. 排序方式

排序方式 给定一个数组 arr 和一个函数 fn&#xff0c;返回一个排序后的数组 sortedArr。你可以假设 fn 只返回数字&#xff0c;并且这些数字决定了 sortedArr 的排序顺序。sortedArr 必须按照 fn 的输出值 升序 排序。 你可以假设对于给定的数组&#xff0c;fn 不会返回重复的…

记录Python链接mysql的数据库的2种操作方式

一、使用pymysql库方式 import pymysqldb pymysql.connect(hostlocalhost,userroot,password123456) #创建链接&#xff0c;在3.8以后好像已经不支持这个种链接方式了&#xff0c; #db pymysql.connect(localhost,root,123456) cursor db.cursor()#拿到游标这样我们就拿到了…

DataX-Web,介绍-安装-部署-启动

使用文档&#xff1a;GitHub - WeiYe-Jing/datax-web: DataX集成可视化页面 目录 1、DataX-Web介绍 2、DataX-Web部署 3、DataX-Web启动命令 1、DataX-Web介绍 GitHub - WeiYe-Jing/datax-web&#xff1a;DataX集成可视化页面&#xff0c;选择数据源即可一键生成数据同步任务…

iOS依赖库版本一致性检测:确保应用兼容性

一、背景 在 iOS 应用开发的世界里&#xff0c;每次 Xcode 更新都带来了新的特性和挑战。最近的 Xcode 15 更新不例外&#xff0c;这次升级引入了对 SwiftUI 的自动强依赖。SwiftUI最低是从 iOS 13 开始支持。 这一变化也带来了潜在的兼容性问题。如果您的项目在升级到 Xcode…

使用 npm 工具高效更新项目依赖包

团队内部会用工具定时检查包的最新版本并通知&#xff0c;以便我们及时跟进社区进展&#xff0c;避免和技术栈出现版本脱节导致无法使用最新特性和优化内容 这里只说明手动查看和更新包的主要几个命令。 npm outdated&#xff1a;检查项目中过时的依赖包及其最新版本。 npm i…

在 Vue 2 中动态赋值 img 标签的 src 属性时显示为图裂

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的全栈工程师 欢迎分享 / 收藏 / 赞 / 在看…

Java-通过Maven导入本地jar包的常用方式

1.首先创建一个用于创建jar包的项目&#xff0c;进行测试 2.测试成功后进行项目打包 3.创建一个要导入本地jar包的项目&#xff0c;在项目下创建lib目录&#xff0c;并将刚才打包好的jar包复制进去 4.在pom.xml文件中引入 5.运行测试

02-攻防世界PHP2

题目 authenticate:证明什么是真的 解题 观察题目可知&#xff0c;访问index.phps可能会有不一样的发现 http://61.147.171.105:51671/index.phps访问该链接&#xff0c;可以得到下面的界面 这里只显示出了部分代码&#xff0c;右键该界面&#xff0c;点击查看源代码&#xf…

引领软件供应链安全 比瓴科技位居安全牛全景图第一

近日&#xff0c;安全牛第十一版《中国网络安全行业全景图》正式发布&#xff0c;比瓴科技入选全景图软件供应链安全赛道中开发流程安全管理、DevSecOps和软件成分分析三个重要细分领域&#xff0c;并位居开发流程安全管控领域第一。 安全牛本次全景图研究工作于23年正式启动&a…

一文了解Activiti7

文章目录 ☃️1.1 Activiti 介绍☃️1.2 Activiti 开发流程☃️1.3 BPMN 2.0 规范是什么☃️1.4 BPMN 2.0 基本流程符号❄️❄️1.4.1 事件 Event❄️❄️1.4.2 活动❄️❄️1.4.3 网关 Gateway ☃️1.5 Activiti API 服务接口❄️❄️1.5.1 核心Service接口及其获取 ☃️1.1 A…

M2 运行 llamafile

安装llamafile很简单&#xff0c;进入官网&#xff0c;按照步骤安装运行即可。 https://github.com/Mozilla-Ocho/llamafile 下载 llava-v1.5-7b-q4.llamafile赋予运行权限chmod x llava-v1.5-7b-q4.llamafile运行 ./llava-v1.5-7b-q4.llamafile -ngl 9999 速度确实是比 olla…

HBase2.x学习笔记

文章目录 一、HBase 简介1、HBase 定义1.1 概述1.2 HBase 与 Hadoop 的关系1.3 RDBMS 与 HBase 的对比1.4 HBase 特征简要 2、HBase 数据模型2.1 HBase 逻辑结构2.2 HBase 物理存储结构2.3 HBase的表数据模型 3、HBase 基本架构3.1 Master3.2 Region Server3.3 Zookeeper3.4 HD…

哪个牌子的电视盒子好用?经销商整理线下热销电视盒子排行榜

在选购电视盒子的时候许多朋友并不了解哪个牌子的电视盒子好用&#xff0c;如何才能买到最满意的电视盒子呢&#xff1f;我身为数码实体店老板&#xff0c;做电视盒子这块有七年了&#xff0c;经常会有用户问我电视盒子相关问题&#xff0c;我按照店内销量整理了电视盒子排行榜…

微信小程序英文版:实现一键切换中英双语版(已组件化)

已经重新优化代码做成了组件&#xff0c;需要可自取&#xff1a;https://github.com/CrystalCAI11/wechat-language-compoment 所有操作都打包在组件里不需要在额外的地方添加代码&#xff0c;直接在你需要的页面里导入组件&#xff0c;再在对应页面的onLoad()里set文本就行了。…