Mysql

什么是Mysql?

  • MySQL 是⼀种关系型数据库, 是开源免费的,并且⽅便扩展,在Java企业级开发中⾮常常⽤。
  • MySQL 是一个真正的多用户、 多线程 SQL 数据库服务器。它能够快速、有效和安全的处理大量的数据。相对于 Oracle 等数据库来说,MySQL 的使用是非常简单的。MySQL 主要目标是快速、健壮和易用。
  • MySQL是开放源代码的,因此任何⼈都可以下载并根据个性化的需要对其进⾏修改。MySQL 的跨平台性,MySQL 不仅可以在 Windows 系列的操作系统上运行,还可以在 UNIX、Linux 和 Mac OS 等操作系统上运行。
  • MySQL数据库是关系型的: 一个关系型数据库将数据存储在不同的表中,而不是将所有的数据存储在一个大的存储区域中。为了提高存储速度,结构化数据是有组织的存放在物理文件中。数据库、表格、视图、行和列等对象的逻辑模型提供了灵活的编程环境。你可以在指向不同表格的不同数据字段中设置对应关系的规则,如一对一、一对多、唯一、必须和可选。数据库强制执行这些规则,因此,在一个设计良好的数据库中,应用程序永远不会看到不一致的、重复的或者孤立的、过期或者丢失的数据。
  • MySQL的默认端⼝号是3306

MyISAM和InnoDB区别

存储引擎作用在表上,默认使用InnoDB。和大多数的数据库不同, MySQL中有一个存储引擎的概念, 针对不同的存储需求可以选择最优的存储引擎。存储引擎就是存储数据,建立索引,更新查询数据等等技术的实现方式 。存储引擎是基于表的,而不是基于库的。所以存储引擎也可被称为表类型。

show engines;--查询当前数据库支持的所有存储引擎
show variables like '%storage_engine%' ; --查看Mysql数据库默认的存储引擎

MyISAM是MySQL的默认数据库引擎(5.5版之前)。虽然性能极佳,⽽且提供了⼤量的特性,包括全⽂索引、压缩、空间函数等,但MyISAM不⽀持事务和⾏级锁,⽽且最⼤的缺陷就是崩溃后⽆法安全恢复。不过,5.5版本之后,MySQL引⼊了InnoDB(事务性数据库引擎),MySQL5.5版本后默认的存储引擎为InnoDB。

⼤多数时候我们使⽤的都是 InnoDB 存储引擎,但是在某些情况下使⽤ MyISAM 也是合适的⽐如读密集的情况下。(如果你不介意 MyISAM 崩溃恢复问题的话)。

两者的对⽐:

  1. 是否⽀持⾏级锁 : MyISAM 只有表级锁,⽽InnoDB ⽀持⾏级锁和表级锁,默认为⾏级锁。

  2. 是否⽀持事务和崩溃后的安全恢复: MyISAM 强调的是性能,每次查询具有原⼦性,其执⾏速度⽐InnoDB类型更快,但是不提供事务⽀持。InnoDB存储引擎提供了具有提交、回滚、崩溃恢复能力的事务安全。但是对比MyISAM的存储引擎,InnoDB写的处理效率差一些,并且会占用更多的磁盘空间以保留数据和索引。InnoDB提供事务,支持事务

  3. 是否⽀持外键: MySQL支持外键的存储引擎只有InnoDB,MyISAM不⽀持。

  4. 是否⽀持MVCC(一种多版本并发控制机制) :仅 InnoDB ⽀持。应对⾼并发事务, MVCC⽐单纯的加锁更⾼效;MVCC只 在 READ COMMITTED 和 REPEATABLE READ 两个隔离级别下⼯作;MVCC可以使⽤ 乐 观(optimistic)锁 和 悲观(pessimistic)锁来实现;

  5. Innodb不支持全文索引,而MyISAM支持全文索引,在涉及全文索引领域的查询效率上MyISAM速度更快高

  6. InnoDB表必须有唯一索引(如主键),而Myisam可以没有

存储引擎的选择:

在选择存储引擎时,应该根据应用系统的特点选择合适的存储引擎。对于复杂的应用系统,还可以根据实际情况选择多种存储引擎进行组合。以下是几种常用的存储引擎的使用环境。

  • InnoDB : 是Mysql的默认存储引擎,用于事务处理应用程序,支持外键。如果应用对事务的完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入和查询意外,还包含很多的更新、删除操作,那么InnoDB存储引擎是比较合适的选择。InnoDB存储引擎除了有效的降低由于删除和更新导致的锁定, 还可以确保事务的完整提交和回滚,对于类似于计费系统或者财务系统等对数据准确性要求比较高的系统,InnoDB是最合适的选择。
  • MyISAM : 如果应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完整性、并发性要求不是很高,那么选择这个存储引擎是非常合适的。

字符集及校对规则

MYSQL的字符集包括字符集(character)和校队规则(collation)两个概念,其中字符集用来定义mysql中存储字符串的方式。校对规则用来你定义比较字符串的方式。字符集和校对规则是一对多的关系,也就是说一种字符集可以包含多种校队规则

一个字符集至少对应着一个校队规则,如果没有设置校队规则,那么mysql会默认使用该字符集的默认校队规则,同样,如果仅仅设置了校队规则而没有选择字符集,那么mysql会使用与设置的校对规则相匹配的字符集

show character set;--查看mysql支持的字符集
show collation like 'gbk%';--查看某个字符集支持的校对规则

每种字符集都有自己特有的编码方式,因此同一个字符,在不同字符集的编码方式下,会产生不同的二进制

常见字符集:

  • ASCII字符集:基于罗马字母表的一套字符集,它采用1个字节的低7位表示字符,高位始终为0。
  • LATIN1字符集:相对于ASCII字符集做了扩展,仍然使用一个字节表示字符,但启用了高位,扩展了字符集的表示范围。
  • GBK字符集:支持中文,字符有一字节编码和两字节编码方式。
  • UTF8字符集:Unicode字符集的一种,是计算机科学领域里的一项业界标准,支持了所有国家的文字字符,utf8采用1-4个字节表示字符。

索引

索引是帮助Mysql高效获取数据的数据结构(有序),这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法

我们平常所说的索引,如果没有特别指明,都是指B+Tree(多路搜索树,并不一定是二叉的)索引。其中聚集索引、复合索引、前缀索引、唯一索引默认都是使用 B+tree 索引,统称为 索引。

MySQL索引使⽤的数据结构主要有BTree索引 和 哈希索引 。对于哈希索引来说,底层的数据结构就是哈希表,因此在绝⼤多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;其余⼤部分场景,建议选择BTree索引。

MySQL的BTree索引使⽤的是B树中的B+Tree,但对于主要的两种存储引擎的实现⽅式是不同的。

  • MyISAM: B+Tree叶节点的data域存放的是数据记录的地址。在索引检索的时候,⾸先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其 data 域的值,然后以 data 域的值为地址读取相应的数据记录。这被称为“⾮聚簇索引”。
  • InnoDB: 其数据⽂件本身就是索引⽂件。相⽐MyISAM,索引⽂件和数据⽂件是分离的,其表数据⽂件本身就是按B+Tree组织的⼀个索引结构,树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据⽂件本身就是主索引。这被称为“聚簇索引(或聚集索引)”。在根据主索引搜索时,直接找到key所在的节点即可取出数据;在根据辅助索引查找时,则需要先取出主键的值,再⾛⼀遍主索引。 因此,在设计表的时候,不建议使⽤过⻓的字段作为主键,也不建议使⽤⾮单调的字段作为主键,这样会造成主索引频繁分裂。

索引是数据库优化最常用也是最重要的手段之一(索引是优化查询效率最有效的方式之一), 通过索引通常可以帮助用户解决大多数的MySQL的性能优化问题。

查询缓存的使用

开启Mysql的查询缓存,**会将执行的SQL语句和对应的查询结果存储到缓存中,**当执行完全相同的SQL语句的时候,服务器就会直接从缓存中读取结果,当数据被修改,之前的缓存会失效,修改比较频繁的表不适合做查询缓存。

缓存虽然能够提升数据库的查询性能,但是缓存同时也带来了额外的开销,每次查询后都要做⼀次缓存操作,失效后还要销毁。

SHOW VARIABLES LIKE 'have_query_cache';    --查看当前的MySQL数据库是否支持查询缓存
SHOW VARIABLES LIKE 'query_cache_type';--查看当前MySQL是否开启了查询缓存

在 /usr/my.cnf 配置中,增加以下配置开启查询缓存 :

query_cache_type=1

配置完毕之后,重启服务既可生效 ;

什么是事务?

事务是逻辑上的⼀组操作,要么都执⾏,要么都不执⾏。

事务最经典也经常被拿出来说例⼦就是转账了。假如⼩明要给⼩红转账1000元,这个转账会涉及到两个关键操作就是:将⼩明的余额减少1000元,将⼩红的余额增加1000元。万⼀在这两个操作之间突然出现错误⽐如银⾏系统崩溃,导致⼩明余额减少⽽⼩红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。

事务的四大特性

  1. 原⼦性(Atomicity): 事务是最⼩的执⾏单位,不允许分割。事务的原⼦性确保动作要么全部完成,要么完全不起作⽤;

  2. ⼀致性(Consistency): 执⾏事务前后,数据保持⼀致,多个事务对同⼀个数据读取的结果是相同的;

  3. 隔离性(Isolation): 并发访问数据库时,⼀个⽤户的事务不被其他事务所⼲扰,各并发事务之间数据库是独⽴的;

  4. 持久性(Durability): ⼀个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发⽣故障也不应该对其有任何影响。

并发事务带来哪些问题?

在典型的应⽤程序中,多个事务并发运⾏,经常会操作相同的数据来完成各⾃的任务(多个⽤户对同⼀数据进⾏操作)。并发虽然是必须的,但可能会导致以下的问题。

脏读(Dirty read): 当⼀个事务正在访问数据并且对数据进⾏了修改,⽽这种修改还没有提交到数据库中,这时另外⼀个事务也访问了这个数据,然后使⽤了这个数据。因为这个数据是还没有提交的数据,那么另外⼀个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。

丢失修改(Lost to modify): 指在⼀个事务读取⼀个数据时,另外⼀个事务也访问了该数据,那么在第⼀个事务中修改了这个数据后,第⼆个事务也修改了这个数据。这样第⼀个事务内的修改结果就被丢失,因此称为丢失修改。 例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被隔离级别

不可重复读(Unrepeatableread): 指在⼀个事务内多次读同⼀数据。在这个事务还没有结束时,另⼀个事务也访问该数据。那么,在第⼀个事务中的两次读数据之间,由于第⼆个事务的修改导致第⼀个事务两次读取的数据可能不太⼀样。这就发⽣了在⼀个事务内两次读到的数据是不⼀样的情况,因此称为不可重复读。

幻读(Phantom read): 幻读与不可重复读类似。它发⽣在⼀个事务(T1)读取了⼏⾏数据,接着另⼀个并发事务(T2)插⼊了⼀些数据时。在随后的查询中,第⼀个事务(T1)就会发现多了⼀些原本不存在的记录,就好像发⽣了幻觉⼀样,所以称为幻读。

不可重复读和幻读区别:

不可重复读的重点是修改⽐如多次读取⼀条记录发现其中某些列的值被修改,幻读的重点在于新增或者删除⽐如多次读取⼀条记录发现记录增多或减少了。

事务的隔离级别有哪些?Mysql默认的隔离级别是?

SQL 标准定义了四个隔离级别:

  • READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
  • **READ-COMMITTED(读取已提交):**允许读取并发事务已经提交的数据,可以阻⽌脏读,但是幻读或不可重复读仍有可能发⽣。
  • REPEATABLE-READ(可重复读): 对同⼀字段的多次读取结果都是⼀致的,除⾮数据是被本身事务⾃⼰所修改,可以阻⽌脏读和不可重复读,但幻读仍有可能发⽣。
  • SERIALIZABLE(可串⾏化): 最⾼的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执⾏,这样事务之间就完全不可能产⽣⼲扰,也就是说,该级别可以防⽌脏读、不可重复读以及幻读。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p8OdBrz8-1632496792479)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210906215007077.png)]

因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是READ-COMMITTED(读取提交内容):

MySQL InnoDB 存储引擎的默认⽀持的隔离级别是 REPEATABLE-READ(可重读)。在 分布式事务 的情况下⼀般会⽤到 SERIALIZABLE(可串⾏化) 隔离级别

SELECT @@tx_isolation;--查看默认隔离级别

锁机制与InnoDB行锁?

锁是计算机协调多个进程或线程并发访问某一资源的机制(避免争抢)。

从对数据操作的粒度分 :

  • 1) 表锁:操作时,会锁定整个表。

  • 2) 行锁:操作时,会锁定当前操作行。

从对数据操作的类型分:

  • 1) 读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响。

  • 2) 写锁(排它锁):当前操作没有完成之前,它会阻断其他写锁和读锁。

从锁的角度来说:表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web 应用;而行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并查询的应用,如一些在线事务处理(OLTP)系统。

MyISAM 存储引擎只支持表锁,这也是MySQL开始几个版本中唯一支持的锁类型。

  • 行锁特点 :偏向InnoDB 存储引擎,开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
  • 表锁特点 :偏向InnoDB 存储引擎,开销小,加锁块;不会出现死锁;锁定粒度最大,发生锁冲突的概率最高,并发度最低。

InnoDB行锁:

行锁特点 :偏向InnoDB 存储引擎,开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

InnoDB 实现了以下两种类型的行锁。

  • 共享锁(S):又称为读锁,简称S锁,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。
  • 排他锁(X):又称为写锁,简称X锁,排他锁就是不能与其他锁并存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁,但是获取排他锁的事务是可以对数据就行读取和修改。

InnoDB存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面带来了性能损耗可能比表锁会更高一些,但是在整体并发处理能力方面要远远由于MyISAM的表锁的。当系统并发量较高的时候,InnoDB的整体性能和MyISAM相比就会有比较明显的优势。

优化建议:

  • 尽可能让所有数据检索都能通过索引来完成,避免无索引行锁升级为表锁。
  • 合理设计索引,尽量缩小锁的范围
  • 尽可能减少索引条件,及索引范围,避免间隙锁
  • 尽量控制事务大小,减少锁定资源量和时间长度
  • 尽可使用低级别事务隔离(在业务层面满足需求的前提下)

InnoDB锁算法:

  • Record lock:记录锁,单个行记录上的锁
  • Gap lock:间隙锁,锁定一个范围,不包括记录本身
  • Next-key lock:record+gap临键锁,锁定一个范围,包含记录本身

详细见:https://stor.51cto.com/art/202108/676123.htm

大表优化

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

限定数据的范围:务必禁⽌不带任何限制数据范围条件的查询语句。⽐如:我们当⽤户在查询订单历史的时候,我们可以控制在⼀个⽉的范围内;

读/写分离:经典的数据库拆分⽅案,主库负责写,从库负责读;

垂直分区:根据数据库⾥⾯数据表的相关性进⾏拆分。 例如,⽤户表中既有⽤户的登录信息⼜有⽤户的基本信息,可以将⽤户表拆分成两个单独的表,甚⾄放到单独的库做分库。简单来说垂直拆分是指数据表列的拆分,把⼀张列⽐较多的表拆分为多张表。如下图所示,这样来说⼤家应该就更容易理解了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zvQSwjEI-1632496792510)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210907100136133.png)]

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

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

⽔平分区

保持数据表结构不变,通过某种策略存储数据分⽚。这样每⼀⽚数据分散到不同的表或者库中,达到了分布式的⽬的。 ⽔平拆分可以⽀撑⾮常⼤的数据量。

⽔平拆分是指数据表⾏的拆分,表的⾏数超过200万⾏时,就会变慢,这时可以把⼀张的表的数据拆成多张表来存放。举个例⼦:我们可以将⽤户信息表拆分成多个⽤户信息表,这样就可以避免单⼀表数据量过⼤对性能造成影响

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JGsm2tmr-1632496792522)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210907100331430.png)]

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

⽔平拆分能够 ⽀持⾮常⼤的数据量存储,应⽤端改造也少,但 分⽚事务难以解决 ,跨节点Join性能较差,逻辑复杂。《Java⼯程师修炼之道》的作者推荐 尽量不要对数据进⾏分⽚,因为拆分会带来逻辑、部署、运维的各种复杂度 ,⼀般的数据表在优化得当的情况下⽀撑千万以下的数据量是没有太⼤问题的(一般以整型值为主的表在千万级以下,字符串为主的表在五百万以下是没有太大问题的)。如果实在要分⽚,尽量选择客户端分⽚架构,这样可以减少⼀次和中间件的⽹络I/O。

不按照业务数据拆分,而是将同一类型的数据,分别放到不同的库/表中。每个分片包含了整体数据集的一部分。比如:

  1. 根据主键 id 拆分,奇数 id 的数据保存在奇数表(db01.t_user_01,db02.t_user_03),偶数 id 的数据保存在偶数表(db01.t_user_02,db02.t_user_04)。
  2. 根据数据创建时间拆分,比如每个月的数据单独成表,每年的数据单独成库。2020年1月创建的数据存在于表 db2020.t_user_01,2020 年 2 月生成的数据存在于表 db2020.t_user_02。即 按月分表,按年分库。

上面两种水平拆分方式各有利弊。在不同的场景下效果也不同。

举例:假如我们以 uid 水平拆分的策略,保存了用户的浏览历史信息。那么当用户在客户端点击查询自己的浏览记录时,就可以一次性查询到最近一个月/半年的浏览记录。因为基于这种拆分策略,同一个用户的浏览记录全部都保存在同一张表中,因此一次查询基本上就可以满足需求;如果是按时间水平分表,保存这类数据,那么在客户端一般就需要做出取舍,比如用户只能查看最近一个月的浏览记录,因为每张表都只保存最多一个月的数据,如果要查看更多,就需要跨表查询。对于大用户量级的产品来说,我们很难满足其需求。

解释一下什么是池化设计思想,什么是数据库连接池?为什么需要数据连接池?

池化设计应该不是⼀个新名词。我们常⻅的如java线程池、jdbc连接池、redis连接池等就是这类设计的代表实现。这种设计会初始预设资源,解决的问题就是抵消每次获取资源的消耗,如创建线程的开销,获取远程连接的开销等。除了初始化资源,池化设计还包括如下这些特征:池⼦的初始值、池⼦的活跃值、池⼦的最⼤值等,这些特征可以直接映射到java线程池和数据库连接池的成员属性中。

和学校打水类似:

单线程的方式:排队一个一个取水,为了不浪费水,每个人接完水后,关掉水龙头,下一个人接的时候再打开水龙头,开水龙和关水龙头可以看成创建和销毁一个线程用于一个人的取水任务。这种方式适合人少的场景。

多线程的方式:多提供几个水龙头,这种方式适合人较多的场景,例如学生宿舍的公共水房。

线程池的方式:提供一个水池,先将水放到水池,然后由多个人同时在水池取水,水龙头可以不用频繁开关,可以支持多人并发取水,但是水池需要专人监管,如监控水池溢出,水池没水,水池取水人员达到上限等。这种方式适合高并发的情况。

由此看来池化思想最大的作用是支持复用, 避免重复的创建销毁带来的开销

数据库连接本质就是⼀个 socket 的连接。我们可以把数据库连接池是看做是维护的数据库连接的缓存,以便将来需要对数据库的请求时可以重⽤这些连接。

我事先创建好几个数据库连接放着,当我的系统需要操作数据库时就从连接池里直接拿连接,并将这个连接标记为 忙 ;用完后在放会池中,标记为 空闲,(它允许应用程序重复使用一个现有的数据库连接,而不是用一个重新建立一个);当连接池里的连接都在被使用,如果此时还要连接,连接池就会在创建新连接放到池里;这些连接的数量,都是在配置文件里由你控制的

为什么用数据库连接池

创建和释放数据库连接非常耗时,频繁地这种操作将占用大量的性能开销,导致网站的响应速度下降,严重的时候可能导致服务器崩溃;数据库连接池可以节省系统许多开销。还减少了用户必须等待建立与数据库的连接的时间。

分库分表之后,id主键如何处理

因为要是分成多个表之后,每个表都是从 1 开始累加,这样是不对的,我们需要⼀个全局唯⼀的id 来⽀持。

⽣成全局 id 有下⾯这⼏种⽅式:

UUID:不适合作为主键,因为太⻓了,并且⽆序不可读,查询效率低。⽐较适合⽤于⽣成唯⼀的名字的标示⽐如⽂件的名字。

数据库⾃增 id : 两台数据库分别设置不同步⻓,⽣成不重复ID的策略来实现⾼可⽤。这种⽅式⽣成的 id 有序,但是需要独⽴部署数据库实例,成本⾼,还会有性能瓶颈。

利⽤ redis ⽣成 id : 性能⽐᫾好,灵活⽅便,不依赖于数据库。但是,引⼊了新的组件造成系统更加复杂,可⽤性降低,编码更加复杂,增加了系统成本。

Twitter的snowflake算法 :Github 地址:https://github.com/twitter-archive/snowflake。

美团的Leaf分布式ID⽣成系统 :Leaf 是美团开源的分布式ID⽣成器,能保证全局唯⼀性、趋势递增、单调递增、信息安全,⾥⾯也提到了⼏种分布式⽅案的对⽐,但也需要依赖关系数据库、Zookeeper等中间件。感觉还不错

⼀条SQL语句在MySQL中如何执⾏的

  • 连接器: 身份认证和权限相关(登录 MySQL 的时候)。
  • 查询缓存: 执行查询语句的时候,会先查询缓存(MySQL 8.0 版本后移除,因为这个功能不太实用)。
  • 分析器: 没有命中缓存的话,SQL 语句就会经过分析器,分析器说白了就是要先看你的 SQL 语句要干嘛,再检查你的 SQL 语句语法是否正确。(词法分析->语法分析)
  • 优化器: 按照 MySQL 认为最优的方案去执行。
  • 执行器: 执行语句,然后从存储引擎返回数据。

简单来说 MySQL 主要分为 Server 层和存储引擎层:

  • Server 层:主要包括连接器、查询缓存、分析器、优化器、执行器等,所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图,函数等,还有一个通用的日志模块 binglog 日志模块。
  • 存储引擎: 主要负责数据的存储和读取,采用可以替换的插件式架构,支持 InnoDB、MyISAM、Memory 等多个存储引擎,其中 InnoDB 引擎有自有的日志模块 redolog 模块。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始就被当做默认存储引擎了。

SQL 等执行过程分为两类:

一类对于查询等过程如下:权限校验—》查询缓存—》分析器—》优化器—》权限校验—》执行器—》引擎

•对于更新等语句执行流程如下:分析器----》权限校验----》执行器—》引擎—redo log prepare—》binlog—》redo log commit

详细参见:https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485097&idx=1&sn=84c89da477b1338bdf3e9fcd65514ac1&chksm=cea24962f9d5c074d8d3ff1ab04ee8f0d6486e3d015cfd783503685986485c11738ccb542ba7&token=79317275&lang=zh_CN%23rd

Mysql高性能优化规范建议

  • 使用连接池:对于访问数据库来说,建立连接的代价是比较昂贵的,因为我们频繁的创建关闭连接,是比较耗费资源的,我们有必要建立 数据库连接池,以提高访问的性能。
  • 减少对MYSQL的访问:即尽量降低无效访问
  • 避免对数据进行重复检索:在编写应用代码时,需要能够理清对数据库的访问逻辑。能够一次连接就获取到结果的,就不用两次连接,这样可以大大减少对数据库无用的重复请求。
  • 增加cache层:在应用中,我们可以在应用中增加 缓存 层来达到减轻数据库负担的目的。缓存层有很多种,也有很多实现方式,只要能达到降低数据库的负担又能满足应用需求就可以。因此可以部分数据从数据库中抽取出来放到应用端以文本方式存储, 或者使用框架(Mybatis, Hibernate)提供的一级缓存/二级缓存,或者使用redis数据库来缓存数据 。
  • 负载均衡:负载均衡是应用中使用非常普遍的一种优化方法,它的机制就是利用某种均衡算法,将固定的负载量分布到不同的服务器上, 以此来降低单台服务器的负载,达到优化的效果。
  • 利用MySQL复制分流查询:通过MySQL的主从复制,实现读写分离,使增删改操作走主节点,查询操作走从节点,从而可以降低单台服务器的读写压力。
  • 采用分布式数据库架构:分布式数据库架构适合大数据量、负载高的情况,它有良好的拓展性和高可用性。通过在多台服务器之间分布数据,可以实现在多台服务器之间的负载均衡,提高访问效率。

一条SQL执行的很慢的原因有哪些?

一个 SQL 执行的很慢,我们要分两种情况讨论:

1、大多数情况下很正常,偶尔很慢,则有如下原因

  • (1)、数据库在刷新脏页,例如 redo log 写满了需要同步到磁盘。
  • (2)、执行的时候,遇到锁,如表锁、行锁。

2、这条 SQL 语句一直执行的很慢,则有如下原因。

  • (1)、没有用上索引:例如该字段没有索引;由于对字段进行运算、函数操作导致无法用索引。
  • (2)、数据库选错了索引

如何书写高质量SQL

1、查询SQL尽量不要使用select *,而是select具体字段。

2、如果知道查询结果只有一条或者只要最大/最小一条记录,建议用limit 1

3、应尽量避免在where子句中使用or来连接条件(使用or可能会使索引失效,从而全表扫描。可以使用union all

4、优化limit分页

5、优化你的like语句(ike很可能让你的索引失效。把% 放关键字后面,还是会走索引的)

6、使用where条件限定要查询的数据,避免返回多余的行

7、尽量避免在索引列上使用mysql的内置函数

8、应尽量避免在 where 子句中对字段进行表达式操作,这将导致系统放弃使用索引而进行全表扫

9、Inner join 、left join、right join,优先使用Inner join,如果是left join,左边表结果尽量小。都满足SQL需求的前提下,推荐优先使用Inner join(内连接),如果要使用left join,左边表数据结果尽量小,如果有条件的尽量放到左边处理。

  • Inner join 内连接,在两张表进行连接查询时,只保留两张表中完全匹配的结果集
  • left join 在两张表进行连接查询时,会返回左表所有的行,即使在右表中没有匹配的记录。
  • right join 在两张表进行连接查询时,会返回右表所有的行,即使在左表中没有匹配的记录。

详细参见:https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247486461&idx=1&sn=60a22279196d084cc398936fe3b37772&chksm=cea24436f9d5cd20a4fa0e907590f3e700d7378b3f608d7b33bb52cfb96f503b7ccb65a1deed&token=1987003517&lang=zh_CN%23rd

10、应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。(使用!=和<>很可能会让索引失效)

11、使用联合索引时,注意索引列的顺序,一般遵循最左匹配原则。(不满足最左原则,索引一般会失效)

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

13、如果插入数据过多,考虑批量插入。(批量插入性能好,更加省时间)

14、在适当的时候,使用覆盖索引。(覆盖索引能够使得你的SQL语句不需要回表,仅仅访问索引就能够得到所有需要的数据,大大提高了查询效率。)

15、慎用distinct关键字(distinct 关键字一般用来过滤重复记录,以返回不重复的记录。在查询一个字段或者很少字段的情况下使用时,给查询带来优化效果。但是在字段很多的时候使用,却会大大降低查询效率。)

16、删除冗余和重复索引(重复的索引需要维护,并且优化器在优化查询的时候也需要逐个地进行考虑,这会影响性能的。)

17、如果数据量较大,优化你的修改/删除语句。(避免同时修改或删除过多数据,因为会造成cpu利用率过高,从而影响别人对数据库的访问。)

18、where子句中考虑使用默认值代替null。

19、不要有超过5个以上的表连接(连表越多,编译的时间和开销也就越大。)

20、exist & in的合理利用

21、尽量用 union all 替换 union(如果使用union,不管检索结果有没有重复,都会尝试进行合并,然后在输出最终结果前进行排序。如果检索结果中不会有重复的记录,推荐union all 替换 union。这样会提高效率。)

22、索引不宜太多,一般5个以内。(索引并不是越多越好,索引虽然提高了查询的效率,但是也降低了插入和更新的效率。)

23、尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型(相对于数字型字段,字符型会降低查询和连接的性能,并会增加存储开销。)

24、索引不适合建在有大量重复数据的字段上,如性别这类型数据库字段(如果索引列有大量重复数据,Mysql查询优化器推算发现不走索引的成本更低,很可能就放弃索引了)

25、尽量避免向客户端返回过多数据量。

26、当在SQL语句中连接多个表时,请使用表的别名,并把别名前缀于每一列上,这样语义更加清晰。

27、尽可能使用varchar/nvarchar 代替 char/nchar。(因为首先变长字段存储空间小,可以节省存储空间。其次对于查询来说,在一个相对较小的字段内搜索,效率更高。)

28、为了提高group by 语句的效率,可以在执行到该语句前,把不需要的记录过滤掉。

29、如何字段类型是字符串,where时一定用引号括起来,否则索引失效(因为不加单引号时,是字符串跟数字的比较,它们类型不匹配,MySQL会做隐式的类型转换,把它们转换为浮点数再做比较。)

30、使用explain 分析你SQL的计划

Mysql数据库面试典籍30+ | 大别山码将相关推荐

  1. Redis数据库面试典籍30+ | 大别山码将

    Redis 什么是Redis? 简单来说 Redis 就是⼀个使⽤ C 语⾔开发的数据库(非关系型的数据库),不过与传统数据库不同的是 Redis 的数据是存在内存中的,也就是它是内存数据库,所以读写 ...

  2. Spring框架面试典籍30+ | 大别山码将

    Spring 什么是Spring框架 Spring 是⼀种轻量级(从大小与开销两方面)开发框架,目的是用于简化企业应用程序的开发,它使得开发者只需要 关心业务需求.常见的配置方式有三种:基于 XML ...

  3. SpringBoot框架面试典籍30+ | 大别山码将

    SpringBoot 什么是SpringBoot? Spring Boot基于Spring,是一个非常好的微服务开发框架,你可以使用它快速的搭建起一个系统,其设计目的是用来简化新Spring应用的初始 ...

  4. JUC多线程面试典籍30+ | 大别山码将

    JUC 什么是线程和进程? 进程:进程是程序的⼀次执⾏过程,是系统运⾏程序的基本单位,因此进程是动态的.系统运⾏⼀个程序即是⼀个进程从创建,运⾏到消亡的过程.在 Java 中,当我们启动 main 函 ...

  5. JVM虚拟机面试典籍30+ | 大别山码将

    JVM面试题总结 介绍java内存区域(运行时数据区) [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n6UJczTB-1632497218260)(C:\Users\ ...

  6. Java集合面试典籍30+ | 大别山码将

    Java集合 说说List,Set,Map三者的区别 List (对付顺序的好帮⼿): 是一个有序容器,存储的元素是有序的.可重复的,允许多个null元素 常用的实现类有 ArrayList.Link ...

  7. Mybatis框架面试典籍30+ | 大别山码将

    Mybatis 什么是MyBatis?优缺点及适用场景 Mybatis 是一款优秀的持久层框架,它支持自定义 SQL.存储过程以及高级映射.MyBatis 免除了几乎所有的 JDBC 代码以及设置参数 ...

  8. Java基础面试典籍60+ | 大别山码将

    java基础 面向对象和面向过程的区别 面向过程:比面向对象性能高:面向过程以步骤划分问题,就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了(蛋炒饭 ...

  9. Qt数据库练习之QSqlTableModel的使用(MySql数据库示例,含源码+注释)

    文章目录 一.操作示例 1.1 修改记录(数据) 1.2 添加记录(数据) 1.3 删除记录(数据) 1.4 取消操作 1.5 排序操作 1.6 查询操作 二.了解QSqlTableModel 三.源 ...

最新文章

  1. 【每日DP】day13、P3147 [USACO16OPEN]262144 (区间DP,2048游戏)难度⭐⭐⭐★
  2. 贵港天气预报软件测试,贵港天气预报15天
  3. 腾讯数据库专家多年运维经验凝聚成简,总结这份595页工作笔记
  4. IndexedDB基本概念
  5. NAB展会新闻:微软和媒体娱乐合作伙伴在Windows Azure平台上发展数字供应链解决方案...
  6. 笔记本电脑怎样连接打印机_“小小”打印机 | 惠普M17w迷你激打
  7. 【Flask】from flask.ext.script import Manager
  8. Atitit 关于微服务的思考与理解 attilax总结 1.1. 架构的历史 微服务发展历史 Web》soa》msa 1 1.2. 微服务最大特点 独立部署 1 2. 微服务的优点 1 2.1.
  9. 微信小程序——简单的售后服务单
  10. KETTLE 下载网址
  11. Diablo II中的各种hacks
  12. 【BIM入门实战】Navisworks2018简体中文安装教程(附安装包下载)
  13. html5判断屏幕锁屏,js实现自动锁屏功能
  14. 用友NC 用户名登录设置步骤
  15. 关于红帽RHCE考试的那些事儿
  16. Set接口介绍、HashSet源码简要分析
  17. 怎样用键盘控制电脑的光标
  18. 手机兼容性测试--testin云测流程
  19. modprobe 找不到文件
  20. 二、结合各种图形库实现各种demo(21-30)

热门文章

  1. 信息与计算机科学是学什么的,信息与计算科学:你猜我是学计算?还是计算机?...
  2. 西门子AmeSim车辆仿真软件在新能源汽车开发中的应用-软件AmeSim2021版分享
  3. 项目管理 | 应用系统适配迁移方法论
  4. CSS盒子模型/PS基操/圆角边框/盒子阴影/文字阴影/案例
  5. 泡泡堂游戏开发 (Python Project)
  6. 华为鸿蒙安全标准,鸿蒙升级标准需达到华为麒麟710芯片及以上型号
  7. Microsoft Store无法下载应用解决办法
  8. [linux小水滴]systrace工具使用简介
  9. 正则表达式验证不能输入汉字
  10. C++学习之路:开篇:杂篇