1. 数据库三大范式什么

什么范式
范式数据库设计时遵循的一种规范不同规范要求遵循不同范式

常用三大范式

举例说明3NF:
1NF
属性不可再分,即表中每个列都不可以再进行拆分

如下学生信息表(student):

idname(姓名)、sex_code(性别代号)、sex_desc(性别描述)、contact(联系方式)

primary key(id)
在这里插入图片描述
如果在查询学生表时经常用到学生的电话号,则应该将联系方式(contact)这一列分为电话号(phone)和地址(address)两列,这样才符合第一范式。

修改使表满足1NF后:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3TNQOBcj-1676683703056)(../../images/image-20230217143559491.png)]

判断是否符合第一范式,列是否可以再分,得看需求,如果将电话号和地址分开才能满足查询需求时,那之前的表设计就是满足1NF的,如果电话号和地址拼接作为一个字段可以满足查询存储需求时,那它就满足1NF。

2NF
在满足1NF的前提下,表中不存在部分依赖,非主键列要完全依赖于主键。(主要是说在联合主键的情况下,非主键列不能只依赖于主键的一部分)

如下学生成绩表(score):

stu_id(学生id)、kc_id(课程id)、score(分数)、kc_name(课程名)

primary key(stu_id, kc_id)
在这里插入图片描述
课程表(kc)   primary key(kc_id)
在这里插入图片描述
将原来的成绩表(score)拆分为成绩表(score)和课程表(kc),而且两个表都符合2NF。

3NF:
在满足2NF的前提下,不存在传递依赖。(A -> B, B -> C, A->C)

如下学生信息表(student):

primary key(id)
在这里插入图片描述
表中sex_desc依赖于sex_code,而sex_code依赖于id(主键),从而推出sex_desc依赖于id(主键);sex_desc不直接依赖于主键,而是通过依赖于非主键列而依赖于主键,属于传递依赖,不符合3NF。

修改表使满足3NF后:

学生表(student)   primary key(id)
在这里插入图片描述
性别代码表(sexcode)   primary key(sex_code)

在这里插入图片描述
将原来的student表进行拆分后,两个表都满足3NF。

什么样的表越容易符合3NF?
非主键列越少的表。(1NF强调列不可再分;2NF和3NF强调非主属性列和主属性列之间关系)

代码表(sexcode),非主键列只有一个sex_desc;

或者将学生表的主键设计primary key(id,name,sex_code,phone),这样非主键列只有address,更容易符合3NF。

ps:

除了三大范式外,还有BC范式和第四范式,但其规范过于严苛,在生产中往往使用不到。

2. 什么是范式和反范式,以及各自优缺点

范式是符合某一种级别关系模式集合构造数据库必须遵循一定的规则。在关系数据库中,这种规则就是范式。
在这里插入图片描述
所以在平时工作中,我们通常是将范式和反范式相互结合使用

3. 索引

1、索引几种类型分类

2、索引的优缺点?

先来说说**优点:**创建索引可以大大提高系统性能

既然增加索引有如此多的优点,为什么不对表中的每一个列都创建一个索引呢?这是因为索引也是有缺点的:

3. 索引设计原则

4. 索引的数据结构

索引的数据结构和具体存储引擎实现有关,MySQL中常用的是 HashB+树 索引。

Hash 和 B+ 树索引的区别

5. 为何使用 B+ 树而非 B 树做索引?

5.1. 先来了解一下 B+ 树和 B 树的区别
5.2. 为什么 B+ 树比 B 树更适合应用于数据库索引?

6. 什么是覆盖索引?

覆盖索引(covering index)指一个查询语句执行只用从索引中就能够取得,不必从数据表读取。 也可以称之为实现了索引覆盖。 如果一个索引包含了(或覆盖了)满足查询语句字段条件的数据就叫做覆盖索引。 一条查询语句符合覆盖索引条件时,sql只需要通过索引就可以返回查询所需要的数据,这样避免了查到索引后再返回表操作,减少I/O提高效率

7. 什么是索引下推?

索引下推(Index condition pushdown 简称 ICP,在 Mysql 5.6 版本上推出的一项用于优化查询技术

在不使用索引下推的情况下,在使用非主键索引进行查询时,存储引擎通过索引检索到数据,然后返回给 MySQL 服务器服务器判断数据是否符合条件

而有了索引下推之后,如果存在某些被索引列的判断条件时,MySQL 服务器将这一部分判断条件传递给存储引擎,然后由存储引擎通过判断索引是否符合 MySQL 服务器传递的条件,只有当索引符合条件时才会将数据检索出来返回给 MySQL 服务器。

索引条件下推优化可以减少存储引擎查询基础表的次数,也可以减少 MySQL 服务器从存储引擎接收数据的次数

4. 存储

4.1. 有哪些常见的存储引擎?

  1. MyISAM:这种引擎是mysql最早提供的。这种引擎又可以分为静态MyISAM、动态MyISAM 和压缩MyISAM三种,不管是何种MyISAM表,目前它都不支持事务,行级锁和外键约束功能
  2. MyISAM Merge引擎:这种类型是MyISAM类型的一种变种。合并表是将几个相同的MyISAM表合并为一个虚表。常应用于日志数据仓库
  3. InnoDB:InnoDB表类型可以看作是对MyISAM的进一步更新产品,它提供了事务、行级锁机制和外键约束功能,也是目前MySQL 默认 的存储引擎。
  4. Memory(heap):这种类型的数据表只存在于内存中。它使用散列索引,所以数据的存取速度非常快。因为是存在于内存中,所以这种类型常应用于临时表中
  5. archive:这种类型只支持selectinsert语句,而且不支持索引。常应用于日志记录聚合分析方面。

4.2. MyISAM 和 InnoDB 的区别

1)InnoDB 支持事务,而 MyISAM 不支持

2)InnoDB 支持外键,而 MyISAM 不支持。因此将一个含有外键的 InnoDB 表 转为 MyISAM 表会失败

3)InnoDB 和 MyISAM 均支持 B+ Tree 数据结构的索引。但 InnoDB 是聚集索引,而 MyISAM 是非聚集索引。

4)InnoDB 不保存表中数据行数执行 select count(*) from table 时需要全表扫描。而 MyISAM 用一个变量记录了整个表的行数速度相当快(注意不能有 WHERE 子句)。

**那为什么 InnoDB 没有使用这样的变量呢?**因为InnoDB的事务特性,在同一时刻表中的行数对于不同事务而言是不一样的。

5)InnoDB 支持表、行(默认)级锁,而 MyISAM 支持表级锁。

InnoDB 的行锁是基于索引实现的,而不是物理记录上。即访问如果没有命中索引,则也无法使用行锁,将要退化表锁

6)InnoDB 必须有唯一索引(如主键),如果没有指定,就会自动寻找或生产一个隐藏列 Row_id 来充当默认主键,而 Myisam 可以没有主键。

4.3. InnoDB引擎四大特性

4.4. InnoDB为何推荐使用自增主键?

自增 ID 可以保证每次插入时 B+ 树索引是从右扩展的,因此相比自定义 ID (如 UUID)可以避免 B+ 树的频繁合并和分裂。如果使用字符串主键和随机主键,会使得数据随机插入,效率比较差。

4.5. 存储结构

4.5.1. 什么是 InnoDB 的页、区、段?

5. 事务

5.1. 什么是事务的四大特性(ACID)?

5.2. 事务的并发问题

脏读、幻读、不可重复读。

5.3. 什么是脏读、幻读和不可重复

不可重复读和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增删除解决不可重复读的问题只需要锁住满足条件的行,解决幻读需要锁表。

5.4. 事务的隔离级别哪些

在这里插入图片描述
串行化隔离级别最高,读未提交级别最低,级别越高,则执行效率就越低,所以在选择隔离级别应该结合实际情况。

MySQL 支持以上四种隔离级别默认为 Repeatable read (可重复读);而 Oracle 只支持 Serializeble(串行化) 级别和 Read committed(读已提交) 两种,其中默认为读已提交。

6. 锁

6.1. 数据库锁的作用以及有哪些锁?

当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制。即锁的作用是解决并发问题

6.2. 隔离级别和锁的关系

1)在 Read Uncommitted 级别下,读取数据不需要加共享锁,这样就不会跟被修改的数据上的排他锁冲突

2)在 Read Committed 级别下,读操作需要加共享锁,但是在语句执行完以后释放共享锁;

3)在 Repeatable Read 级别下,读操作需要加共享锁,但是在事务提交之前并不释放共享锁,也就是必须等待事务执行完毕以后才释放共享锁;

4)在 SERIALIZABLE 级别下,限制性最强,因为该级别锁定整个范围的键,并一直持有锁,直到事务完成。

6.3. InnoDB 中的锁算法

6.4. 什么是快照读和当前读?

快照 就是读取的是快照数据,不加锁的简单 Select属于快照读。

SELECT * FROM player WHERE ...

当前读 就是读的是最新数据,而不是历史的数据。加锁的 SELECT,或者对数据进行增删改都会进行当前读。

SELECT * FROM player LOCK IN SHARE MODE;
SELECT FROM player FOR UPDATE;
INSERT INTO player values ...
DELETE FROM player WHERE ...
UPDATE player SET ...

6.5. 什么是MVCC以及实现

MVCC 的英文全称是 Multiversion Concurrency Control中文意思是多版本并发控制,可以做到读写互相不阻塞,主要用于解决不可重复读和幻读问题时提高并发效率。

其原理是通过数据行的多个版本管理实现数据库的并发控制简单来说就是保存数据的历史版本。可以通过比较版本号决定数据是否显示出来。读取数据时候不需要加锁可以保证事务的隔离效果

7. 视图

7.1. 为什么要使用视图?什么是视图

7.2. 视图有哪些特点?

视图的特点如下:

视图的操作包括创建视图,查看视图,删除视图和修改视图。

7.3. 视图的使用场景哪些

视图根本用途简化sql查询,提高开发效率。如果说还有另外一个用途那就是兼容老的表结构

下面是视图的常见使用场景

7.4. 视图的优点

  1. 查询简单化。视图能简化用户的操作
  2. 数据安全性。视图使用户能以多种角度看待同一数据,能够对机密数据提供安全保护
  3. 逻辑数据独立性。视图对重构数据库提供了一定程度的逻辑独立性

7.5. 视图的缺点

  1. 性能。数据库必须把视图的查询转化成对基本表的查询,如果这个图是由一个复杂多表查询所定义,那么,即使是视图的一个简单查询,数据库也把它变成一个复杂的结合体,需要花费一定的时间。

  2. 修改限制。当用户试图修改视图的某些行时,数据库必须把它转化为对基本表的某些行的修改。事实上,当从视图中插入或者删除时,情况也是这样。对于简单视图来说,这是很方便的,但是,对于比较复杂的视图,可能是不可修改的

    这些视图有如下特征:1.有UNIQUE等集合操作符的视图。2.有GROUP BY子句的视图。3.有诸如AVGSUMMAX等聚合函数的视图。 4.使用DISTINCT关键字的视图。5.连接表的视图(其中有些例外)

7.6. 什么是游标

8. 存储过程函数

什么是存储过程

哪些优缺点?

优点

  1. 存储过程是预编译过的,执行效率高。
  2. 存储过程代码直接存放于数据库中,通过存储过程名直接调用,减少网络通讯。
  3. 安全性高,执行存储过程需要有一定权限用户
  4. 存储过程可以重复使用,减少数据库开发人员工作量

缺点

  1. 调试麻烦,但是用 PL/SQL Developer 调试很方便!弥补这个缺点。
  2. 移植问题,数据库端代码当然是与数据库相关的。但是如果是做工程项目,基本不存在移植问题。
  3. 重新编译问题,因为后端代码是运行前编译的,如果带有引用关系对象发生改变时,受影响的存储过程、包将需要重新编译(不过也可以设置运行时刻自动编译)。
  4. 如果在一个程序系统中大量的使用存储过程,到程序交付使用的时候随着用户需求的增加会导致数据结构的变化,接着就是系统相关问题了,最后如果用户想维护系统可以说是很难很难、而且代价是空前的,维护起来更麻烦。

9. 触发器

什么是触发器触发器的使用场景有哪些?

使用场景

MySQL中都有哪些触发器?

在MySQL数据库中有如下六种触发器:

10. 常用的SQL语句

SQL语句主要分为哪几类

  • 数据定义语言DDL(Data Ddefinition Language)CREATE,DROP,ALTER

    主要为以上操作 即对逻辑结构等有操作的,其中包括表结构,视图和索引。

  • 数据查询语言DQL(Data Query Language)SELECT

    这个较为好理解 即查询操作,以select关键字。各种简单查询,连接查询等 都属于DQL。

  • 数据操纵语言DML(Data Manipulation Language)INSERT,UPDATE,DELETE

    主要为以上操作 即对数据进行操作的,对应上面所说的查询操作 DQL与DML共同构建了多数初级程序员常用的增删改查操作。而查询是较为特殊的一种 被划分到DQL中。

  • 数据控制功能DCL(Data Control Language)GRANT,REVOKE,COMMIT,ROLLBACK

    主要为以上操作 即对数据库安全性完整性等有操作的,可以简单的理解权限控制等。

SQL语句的语法顺序

  1. SELECT

  2. FROM

  3. JOIN

  4. ON

  5. WHERE

  6. GROUP BY

  7. HAVING

  8. UNION : 将多个查询结果合并(默认去掉重复的记录)

  9. ORDER BY

  10. LIMIT

    在这里插入图片描述

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

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

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联合使用

11. 主从复制

1、什么是主从复制?

主从复制用来建立一个与主数据库完全一样的数据库环境,即从数据库。主数据库一般是准实时业务数据库。

2、主从复制的作用

3、主从复制的架构

联级复制架构只是在一主多从的基础上,再主库和各个从库之间增加了一个二级主库 Master2,这个二级主库仅仅用来将一级主库推送给它的 Binlog 日志推送各个从库,以此来减轻一级主库的推送压力。
在这里插入图片描述

4、主从复制的实现原理?

数据库有个 binlog 二进制文件,记录了数据可执行的所有 SQL 语句。主从同步目标就是把主数据库的 binlog 文件中的 SQL 语句复制到从数据库,让其在从数据的 relaylog 文件中再执行一次这些 SQL 语句即可

具体实现需要三个线程

5、什么是异步复制和半同步

MySQL 的主从复制有两种复制方式,分别是 异步复制同步复制

另外,在半同步复制时,如果主库的一个事务提交成功了,在推送到从库的过程当中,从库宕机了或网络故障,导致从库并没有接收到这个事务的Binlog,此时主库会等待一段时间(这个时间由rpl_semi_sync_master_timeout毫秒数决定),如果这个时间过后还无法推送到从库,那 MySQL 会自动从半同步复制切换为异步复制,当从库恢复正常连接到主库后,主库又会自动切换回半同步复制。

同步复制的“半”体现在,虽然主从库的Binlog是同步的,但主库不会等待从库执行完Relay-log后才返回,而是确认从库接收到Binlog,达到主从Binlog同步的目的后就返回了,所以从库的数据对于主库来说还是有延时的,这个延时就是从库执行Relay-log的时间。所以只能称为半同步。

6、主从中常见问题以及解决?

问题 :
1)主库宕机后,数据可能丢失。

​ 2)从库只有一个sql Thread,主库写压力大,复制很可能延时

**解决: **
1)半同步复制:确保事务提交后 binlog 至少传输到一个从库 ,解决数据丢失的问题。

​ 2)并行复制:从库多线程apply binlog,解决从库复制延迟的问题。

12. 调优

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

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

怎么优化SQL查询语句吗

  1. 对查询进行优化,应尽量避免全表扫描,首先应考虑whereorder 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语句的。分析你的查询语句或是表结构的性能瓶颈。

大表数据查询,怎么优化

  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数据库中,直接返回即可

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

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

主键使用自增ID还是UUID?

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

总之,在数据量大一些的情况下,用自增主键性能会好一些。
关于主键是聚簇索引,如果没有主键,InnoDB会选择一个唯一键来作为聚簇索引,如果没有唯一键,会生成一个隐式的主键。

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

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

如何优化长难的查询语句

  • 分析是一个复杂查询还是多个简单查询速度快
  • 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 likeabc%’
    复制代码
    
  • 10.不要在 where 子句中的“=”左边进行函数算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

数据库优化

为什么要优化

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

数据库结构优化

  • 一个好的数据库设计方案对于数据库的性能往往会起到事半功倍的效果
  • 需要考虑数据冗余、查询和更新的速度、字段的数据类型是否合理等多方面的内容。

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

  • 对于字段较多的表,如果有些字段的使用频率很低,可以将这些字段分离出来形成新表。
  • 因为当一个表的数据量很大时,会由于使用频率低的字段的存在而变慢

增加中间表

  • 对于需要经常联合查询的表,可以建立中间表以提高查询效率。
  • 通过建立中间表,将需要通过联合查询的数据插入到中间表中,然后将原来的联合查询改为对中间表的查询。

增加冗余字段

  • 设计数据表时应尽量遵循范式理论的规约,尽可能的减少冗余字段,让数据库设计看起来精致、优雅。但是,合理加入冗余字段可以提高查询速度。
  • 表的规范化程度越高,表和表之间的关系越多,需要连接查询的情况也就越多,性能也就越差。

注意:

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

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

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

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

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

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

1、垂直分区

在这里插入图片描述

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

在这里插入图片描述

适用场景

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

缺点

3、水平分区
  • 保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。 水平拆分可以支撑非常大的数据量
  • 水平拆分是指数据表行的拆分,表的行数超过200万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放。举个例子:我们可以将用户信息表拆分成多个用户信息表,这样就可以避免单一表数据量过大对性能造成影响。

在这里插入图片描述

  • 水品拆分可以支持非常大的数据量。需要注意的一点是:分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义,所以 水平拆分最好分库
  • 水平拆分能够 支持非常大的数据量存储,应用端改造也少,但 分片事务难以解决 ,跨界点Join性能较差,逻辑复杂
《Java工程师修炼之道》的作者推荐 尽量不要对数据进行分片,因为拆分会带来逻辑、部署运维的各种复杂度 ,一般的数据表在优化得当的情况下支撑千万以下的数据量是没有太大问题的。如果实在要分片,尽量选择客户端分片架构,这样可以减少一次和中间件网络I/O。
4、水平分表:
  • 表很大,分割后可以降低在查询时需要读的数据和索引的页数,同时也降低了索引的层数,提高查询次数

在这里插入图片描述

适用场景

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

水平切分的缺点

  • 1、给应用增加复杂度,通常查询时需要多个表名,查询所有数据都需UNION操作
  • 2、在许多数据库应用中,这种复杂度会超过它带来的优点,查询时会增加读一个索引层的磁盘次数
数据库分片的两种常见方案
分库分表后面临的问题
  • 事务支持 分库分表后,就成了分布式事务了。如果依赖数据库本身的分布式事务管理功能去执行事务,将付出高昂的性能代价; 如果由应用程序去协助控制,形成程序逻辑上的事务,又会造成编程方面的负担。

  • 跨库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的场合还是比较多的,twittersnowflake解决了这种需求,实现也还是很简单的,除去配置信息,核心代码就是毫秒级时间41位 机器ID 10位 毫秒内序列12位。
  • 跨分片的排序分页问题

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

    在这里插入图片描述

原文地址:https://blog.csdn.net/QRLYLETITBE/article/details/129096940

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_40590.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注