本文参考了https://blog.csdn.net/weixin_39666736/article/details/104530984

先复习下SQL

https://www.w3cschool.cn/sql/l4711oyw.html 去这里复习吧QWQ

  1. SELECT column_1,column_2... AS column_new_name1,column_new_name2
  2. FROM TABLE1
  3. INNER JOIN/LEFT JOIN/RIGHT JOIN/FULL JOIN TABLE2 ON blabla
  4. WHERE TABLE1.column_x=TABLE2.column_y
  5. Group By ...[Having ...]
  6. ORDER BY... [ASC/DESC]
  7. LIMIT ... OFFSET ...

大的框架是 SELECT ... FROM ... WHERE...
两个筛选 WHEREHAVING where跟的是数据表里存在的字段,having是从已经筛选出来的字段里再筛选

数据库三大范式

第一范式1NF:数据表每一列都是不可分割的原子数据项
第二范式2NF:每一列都必须和主键相关,不能和主键的部分相关
第三范式3NF:确保数据表每一列和主键直接相关,不能间接相关

mysql为啥选择B+树作为他的存储结构,为啥不选Hash、二叉、红黑树

哈希索引无序,不能顺序查找,哈希冲突
平衡二叉树 树越高查询速度越慢
image.png

B树和B+树的区别

为什么是B+树而不是B树呢,因为它内节点不存储data,这样一个节点就可以存储更多的key

B树:每个节点都存储key和data,所有节点组成这棵树,并且叶子节点指针为null。
image.png
B+树:只有叶子节点存储data,叶子节点包含了这棵树的所有键值,叶子节点不存储指针。
image.png

mysql如何实现分库分表

主要从3点来谈:

  1. 分库分表解决了什么问题
  2. 大体实现方法 如分库怎么分 分表可以怎么分(横向/纵向)
  3. 具体谈sql语句怎么写

数据库分表可以解决单表海量数据的查询性能问题,分库可以解决单台数据库的并发访问压力问题。
https://blog.csdn.net/qq_33936481/article/details/73691331?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_utm_term-0&spm=1001.2101.3001.4242

https://blog.csdn.net/weixin_53749517/article/details/111407959?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-1&spm=1001.2101.3001.4242

image.png
image.png

引擎(innodb和myisam的区别)

引擎是什么?
MySQL中的数据、索引以及其他对象是如何存储的,是一套文件系统的实现。

常用的存储引擎有以下:

  • Innodb引擎:Innodb引擎提供了对数据库ACID事务的支持。并且还提供了行级锁和外键的约束。它的设计的目标就是处理大数据容量的数据库系统。
  • MyIASM引擎(原本Mysql的默认引擎):不提供事务的支持,也不支持行级锁和外键。

image.png
———————————————————
image.png

MyISAM(麦艾怎)索引与InnoDB索引的区别?

  • Myisam 非聚簇索引
  • InnoDB 聚簇索引

image.png

什么是聚簇索引,什么是非聚簇索引

image.png

InnoDB引擎的4大特性

  • 插入缓冲(insert buffer)
  • 二次写(double write)
  • 自适应哈希索引(ahi)
  • 预读(read ahead)

https://blog.csdn.net/weixin_34281537/article/details/90590664?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161714817516780262562013%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=161714817516780262562013&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-1-90590664.first_rank_v2_pc_rank_v29&utm_term=innodb%E7%9A%84%E6%96%B0%E7%89%B9%E6%80%A7

存储引擎选择

如果没有特别的需求,使用默认的Innodb即可。
MyISAM:以读写插入为主的应用程序,比如博客系统、新闻门户网站。
Innodb:更新(删除)操作频率也高,或者要保证数据的完整性;并发量高,支持事务和外键。比如OA自动化办公系统。

分库的时候,MyISAM适合读,因为对全表查询有优化,Innodb适合写,因为并发高。

Mysql的锁的类型

  • 基于锁的属性分类:
    • 共享锁:又称读锁,简称S锁。当一个事务为数据加上读锁之后,其他事务就只能加读锁,而不能对数据库加写锁。
    • 排他锁:又称写锁,简称X锁。当一个事务为数据加上写锁,其他请求将不能为数据加任何锁。避免了脏数据和脏读问题。
  • 基于锁的粒度分类:
    • 行级锁(InnoDB) 上锁的时候锁住的是表对一行或者多行记录(有死锁)
    • 表级锁(InnoDB、Myisam) 上锁的时候锁的整个表
    • 记录锁 属于行锁的一种,但是只锁一条记录,命中条件字段必须是唯一
    • 页级锁(BDB引擎)行级锁和表级锁中间的一种锁,一次锁定相邻的一组记录(会出现死锁)
    • 间隙锁 行锁的一种,锁住的是表记录的某一个区间,遵循左开右闭原则。
    • 邻键锁 InnoDB的行锁默认算法。他是记录锁和间隙锁的组合,会把查询出来的记录和查询的间隙都锁住。(左闭右闭)
  • 基于锁的状态分类:
    • 意向共享锁 : 当一个事务试图对整个表加共享锁之前,首先要获得这个表的意向共享锁
    • 意向排他锁

InnoDB引擎的行锁是怎么实现的?
基于引擎完成行锁

InnoDB储存引擎的锁的算法?
邻键锁 (记录锁 + 间隙锁)

数据库的乐观锁和悲观锁是什么?怎么实现的?

数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。实现方式:使用数据库中的锁机制

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来,通过version的方式来进行锁定。实现方式:乐观锁一般会使用版本号机制或CAS算法实现。

两种锁的使用场景

从上面对两种锁的介绍,我们知道两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。

但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。

什么是死锁?怎么解决?

死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。

常见的解决死锁的方法
1、如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。
2、在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;
3、对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;

如果业务处理不好可以用分布式事务锁或者使用乐观锁

事务的基本特性 ACID,怎么保证

原子性:一个事务操作要么全成功,要么全部失败
一致性(目的):数据库从一个一致性的状态转转换到另外一个一致性的状态(通过其他三性保证一致性)
隔离性:一个事务的修改在最终提交前,对其他事务是不可见的
持久性:事务一旦提交,所做的修改就会永久保存到数据库中

A 原子性由undo logo日志保证,他记录了需要回滚的日志信息,事务回滚时撤销已经执行成功的sql
C 一致性由其他三大特性保证
I 隔离性由MVCC保证
D 持久性由内存+redo log保证,msyql修改数据同时在内存和redo log记录这次操作,宕机的时候可以从redo log中恢复

undo logo(反向执行sql语句) /redo log 是Innodb引擎级别

PS:补充一个概念 binlog日志,是MySQL service级别的,用于主从同步。
image.png

mysql主从同步原理

image.png
image.png

mysql默认隔离级别

1.未提交读:允许别的事务,去读这个事务未提交之前的数据
read uncommited可能出现脏读

2.提交读:一个事务所做的修改在提交之前对其他事务是不可见的
read commit解决了脏读,可能出现 不可重复读

3.可重复读:同一个事务在多次读取同一数据的结果是一样的
解决了 不可重复读,可能出现幻读
注:MySQL的默认隔离级别就是 Repeatable read

4.可串行化:逐个执行事务提交了之后才会继续执行下一个事务
事务顺序执行,可以避免幻读
image.png

脏读、不可重复读、幻读是什么?

脏读:通俗的讲,一个事务在处理过程中读取了另外一个事务未提交的数据。
可重复读 :表示, 你随便读,读多少次都没事,
不可重复读表示**: 事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。**你不要重复读了,不然结果可能不一样(同一个事务中) 不可重复读就是读到是已经提交读数据,但是实际上是违反了事务读一致性原则。
幻读:事务B以插入或删除行等方式来修改事务A的结果集,然后提交,事务A再次读的时候就读到了这个改变的数据。

什么是MVCC

多版本并发控制:读取数据的时候通过一种类似快照的方式将数据保存下来,这样读锁和写锁就不冲突了,不同的事务session会看到自己特定版本的数据,版本链。

MVCC只会在可重复读和不可重复读两个隔离级别下工作。

聚簇索引(innodb)记录中有两个必要的隐藏列:
trx_id: 用来存储每次对某条聚簇索引记录进行修改时候的事务ID
roll_pointer: 每次对哪条聚簇索引记录有修改的时候,都会把老版本写入undo log中,roll_pointer就是存了一个指针,指向了这条聚簇索引记录对上一个版本。

已提交读和可重复读的区别就在于他们生成ReadView的策略不同
image.png
image.png

用JDBC来实现访问数据库记录步骤(了解)

1、通过驱动器管理器获取连接接口。
2、获得Statement或它的子类。
3、限制Statement中的参数。
4、执行Statement。
5、查看返回的行数是否超出范围。
6、关闭Statement。
7、处理其它的Statement
8、关闭连接接

什么是索引,索引的原理

索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。

索引是一种数据结构。数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B+树。

更通俗的说,索引就相当于目录。为了方便查找书中的内容,通过对内容建立索引形成目录。索引是一个文件,它是要占据物理空间的。
————————————————
索引的原理:就是把无序的数据变成有序的查询

  1. 把创建了索引的列的内容进行排序
  2. 对排序结果生成倒排表
  3. 在倒排表内容上拼上数据地址链
  4. 在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据。

为什么要创建索引呢(优点)?

这是因为,创建索引可以大大提高系统的性能。
第一,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
第二,可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
第三,可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
第四,在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序
的时间。
第五,通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

索引优缺点

索引的优点

  • 可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
  • 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

索引的缺点

  • 时间方面:创建索引和维护索引要耗费时间,具体地,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执行效率;
  • 空间方面:索引需要占物理空间。

慢查询(重点)

慢查询的优化首先要搞明白慢的原因是什么。
条件查询没有命中索引是load了不需要的数据列还是数据量太大
所以优化是针对这三个方向来的:

  • 首先分析语句,看看是否load了额外的数据。
  • 分析sql的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能命中索引。
  • 如果对语句的优化已经无法进行,可以考虑分表分库。

    索引类型

    主键索引: 数据列不允许重复,不允许为NULL,一个表只能有一个主键。
    唯一索引: 数据列不允许重复,允许为NULL值,一个表允许多个列创建唯一索引。
    普通索引: 基本的索引类型,没有唯一性的限制,允许为NULL值。
    全文索引: 是目前搜索引擎使用的一种关键技术。

大表怎么优化?

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

  • 限定数据的范围: 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内。;
  • 读/写分离: 经典的数据库拆分方案,主库负责写,从库负责读;
  • 缓存: 使用MySQL的缓存,另外对重量级、更新少的数据可以考虑使用应用级别的缓存;
  • 还有就是通过分库分表的方式进行优化,主要有垂直分表和水平分表

其他 小知识点与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
主要为以上操作 即对数据库安全性完整性等有操作的,可以简单的理解为权限控制等。

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

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

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)

什么是子查询

  1. 条件:一条SQL语句的查询结果做为另一条查询语句的条件或查询结果
  2. 嵌套:多条SQL语句嵌套使用,内部的SQL查询语句称为子查询。

UNION与UNION ALL的区别?

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

drop、delete与truncate的区别

image.png

mysql中 in 和 exists 区别

mysql中的in语句是把外表和内表作hash 连接,而exists语句是对外表作loop循环,每次loop循环再对内表进行查询。一直大家都认为exists比in语句的效率要高,这种说法其实是不准确的。这个是要区分环境的。

如果查询的两个表大小相当,那么用in和exists差别不大。

如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in。
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,易于报表展示

FLOAT和DOUBLE的区别是什么?

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

mysql 分页

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

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

为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1:
mysql> SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last.

如果只给定一个参数,它表示返回最大的记录行数目:
mysql> SELECT * FROM table LIMIT 5; //检索前 5 个记录行

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

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

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

主键使用自增ID还是UUID?

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

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

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

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

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

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

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

  • 访问数据太多导致查询性能下降
  • 确定应用程序是否在检索大量超过需要的数据,可能是太多行或列
  • 确认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语句,然后根据SQL语句可能低效的原因做排查,先从索引着手,如果索引没有问题,考虑以上几个方面,数据访问的问题,长难查询句的问题还是一些特定类型优化的问题,逐一回答。

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=

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 飙升,这种情况就需要跟应用一起来分析为何连接数会激增,再做出相应的调整,比如说限制连接数等