什么是存储过程?
实际开发过程中很少使用存储过程。(因此暂且跳过)
存储过程就是数据库里面内置的编程语言,类似于Java。
存储过程的优点和缺点?
优点:速度快。
解释:若是在Java程序不断处理数据库数据,再返回给数据库,这会造成很大的通信开销。若是在数据库中编写存储过程(处理数据库的函数),Java程序去调用该过程,则会降低通信开销。
缺点:移植性差。编写难度大。维护性差。
mysql数据库的存储过程,到了orcale数据库不可以用。
存储引擎概述
注意:存储引擎跟存储过程没有任何关系。
存储引擎的作用:决定了数据在磁盘上存取和访问的方式。为了适应不同的业务场景,开发出了不同的存储引擎。典型的存储引擎有:
- InnoDB引擎支持事务和行级锁定(例如间隙锁与记录锁),适用于需要高并发读写的应用;
- MyISAM引擎不支持事务,但适用于读操作较多的应用;
- Memory引擎数据全部存储在内存中,不支持事务,适用于对读写速度要求很高的应用等等。
一般情况下存储引擎不用改默认innoDB,只有在要满足其他业务需求时才要改。
MySQL支持哪些存储引擎
使用show engines \G;
命令可以查看所有的存储引擎:
Support
是Yes
的表示支持该存储引擎。当前MySQL的版本是8.0.33
MySQL默认的存储引擎是:InnoDB
指定和修改存储引擎
指定存储引擎
指定存储引擎的示例:
代码:CREATE TABLE my_table (column1 INT, column2 VARCHAR(50)) ENGINE = InnoDB;
解释:创建了一个名为my_table的表,并指定了使用InnoDB存储引擎。
修改存储引擎
一般用不着。因为改了,检索算法变了,可能导致数据的丢失。
修改存储引擎的示例:
代码:ALTER TABLE my_table ENGINE = MyISAM;
解释:使用ALTER TABLE语句将my_table表的存储引擎修改为MyISAM。
修改存储引擎需要考虑的点:
- 修改存储引擎可能需要执行复制表的操作,因此可能会造成数据的丢失或不可用。确保在执行修改之前备份你的数据。
- 不是所有的存储引擎都支持相同的功能。要确保你选择的新存储引擎支持你应用程序所需的功能。
- 修改表的存储引擎可能会影响到现有的应用程序和查询。确保在修改之前评估和测试所有的影响。
- ALTER TABLE语句可能需要适当的权限才能执行。确保你拥有足够的权限来执行修改存储引擎的操作。
索引(超级重要)
什么是索引
相当于书的目录。,对于MySQL数据库而言,索引对应的数据结构是B+树。
索引的创建和删除
主键和unique约束的字段会自动添加索引。
查看某张表上添加了哪些索引
show index from 表名;
给指定的字段添加索引
建表时添加索引:
CREATE TABLE emp (
...
name varchar(255),
...
INDEX idx_name (name)
);
如果表已经创建好了,后期给字段添加索引
ALTER TABLE emp ADD INDEX idx_name (name);
也可以这样添加索引:
create index idx_name on emp(name);
删除指定字段上的索引
ALTER TABLE emp DROP INDEX idx_name;
索引的分类
不同的存储引擎
有不同的索引类型和实现:
- 按照数据结构分类:
- B+树 索引(mysql的InnoDB存储引擎采用的就是这种索引)采用 B+树 的数据结构
- Hash 索引(仅
memory
存储引擎支持):采用 哈希表 的数据结构
- 按照物理存储分类:
- 聚集索引:索引和表中数据在一起,数据存储的时候就是按照索引顺序存储的。一张表只能有一个聚集索引。
- 非聚集索引:索引和表中数据是分开的,索引是独立于表空间的,一张表可以有多个非聚集索引。
- 按照字段特性分类:
- 主键索引(primary key)
- 唯一索引(unique)
- 普通索引(index)
- 全文索引(fulltext:仅
InnoDB和MyISAM
存储引擎支持)
- 按照字段个数分类:
- 单列索引、联合索引(也叫复合索引、组合索引)
B+树经典面试题
**经典面试题:**mysql为什么选择B+树作为索引的数据结构,而不是B树?
- 非叶子节点上可以存储更多的键值,阶数可以更大,更矮更胖,磁盘IO次数少,数据查询效率高。
- 所有数据都是有序存储在叶子节点上,让范围查找,分组查找效率更高。
- 数据页之间、数据记录之间采用链表链接,让升序降序更加方便操作。
**经典面试题:**如果一张表没有主键索引,那还会创建B+树吗?
当一张表没有主键索引时,默认会使用一个隐藏的内置的聚集索引(clustered index)。这个聚集索引是基于表的物理存储顺序构建的,通常是使用B+树来实现的。
其他索引及相关调优
Hash索引
支持Hash索引的存储引擎有:
- InnoDB(不支持手动创建Hash索引,系统会自动维护一个
自适应的Hash索引
)- 对于InnoDB来说,即使手动指定了某字段采用Hash索引,最终
show index from 表名
的时候,还是BTREE
。
- 对于InnoDB来说,即使手动指定了某字段采用Hash索引,最终
- Memory(支持Hash索引)
Hash索引底层的数据结构就是哈希表。一个数组,数组中每个元素是链表。和java中HashMap一样。哈希表中每个元素都是key value结构。key存储索引值
,value存储行指针
。
Hash索引优缺点:
- 优点:只能用在等值比较中,效率很高。例如:name=‘孙悟空’
- 缺点:不支持排序,不支持范围查找。
聚集索引和非聚集索引
聚集索引:索引值与数据存放在一起。
非聚集索引:索引值与数据不存放在一起。
存储引擎是InnoDB的,主键上的索引属于聚集索引。
存储引擎是MyISAM的,任意字段上的索引都是非聚集索引。
InnoDB的物理存储方式:当创建一张表t_user,并使用InnoDB存储引擎时,会在硬盘上生成这样一个文件:
- t_user.ibd (InnoDB data表索引 + 数据)
- t_user.frm (存储表结构信息)
MyISAM的物理存储方式:当创建一张表t_user,并使用MyISAM存储引擎时,会在硬盘上生成这样一个文件:
- t_user.MYD (表数据)
- t_user.MYI (表索引)
- t_user.frm (表结构)
注意:从MySQL8.0开始,不再生成frm文件了,引入了数据字典,用数据字典来统一存储表结构信息,例如:
- information_schema.TABLES (表包含了数据库中所有表的信息,例如表名、数据库名、引擎类型等)
- information_schema.COLUMNS(表包含了数据库中所有表的列信息,例如列名、数据类型、默认值等)
聚集索引的原理图:(B+树,叶子节点上存储了索引值 + 数据)
非聚集索引的原理图:(B+树,叶子节点上存储了索引值 + 行指针)
聚集索引的优点和缺点:
- 优点:聚集索引将数据存储在索引树的叶子节点上。可以减少一次查询,因为查询索引树的同时可以获取数据。
- 缺点:对数据进行修改或删除时需要更新索引树,会增加系统的开销。
二级索引(重点)
二级索引属于非聚集索引。
一张表上的主键是聚集索引,他的非主键是二级索引,非主键二级索引的叶子节点并不存放数据,而是存放该条数据对应的主键值对应的索引,然后再查B+树,找到该数据。
有表t_user,id是主键。age是非主键。在age字段上添加的索引称为二级索引。(所有非主键索引都是二级索引)
二级索引的数据结构:
二级索引的查询原理:
假设查询语句为:
select * from t_user where age = 30;
为什么会“回表”?因为使用了select *
避免“回表【回到原数据表】”是提高SQL执行效率的手段。例如:select id from t_user where age = 30; 这样的SQL语句是不需要回表的。
覆盖索引
是基于多列索引的
覆盖索引(Covering Index),查询需要的所有列都可以从索引中提取到,而不需要再去查询实际数据行获取查询所需数据。
假设有一个用户表(user)包含以下列:id, username, email, age。
常见的查询是根据用户名查询用户的邮箱。如果为了提高这个查询的性能,可以创建一个覆盖索引,包含(username, email)这两列。
创建覆盖索引的SQL语句可以如下:
CREATE INDEX idx_user_username_email ON user (username, email);
当执行以下查询时:
SELECT email FROM user WHERE username = 'lucy';
值得注意的是,覆盖索引的创建需要考虑查询的字段选择。如果查询需要的字段较多,可能需要创建包含更多列的覆盖索引,以满足完全覆盖查询的需要。
覆盖索引具有以下优点:
- 提高查询性能:覆盖索引能够满足查询的所有需求,同时不需要访问表中的实际数据行,从而可以提高查询性能。这是因为DBMS可以直接使用索引来执行查询,而不需要从磁盘读取实际的数据行。
- 减少磁盘和内存访问次数:当使用覆盖索引时,DBMS不需要访问实际的数据行。这样可以减少磁盘和内存访问次数,从而提高查询性能。
- 减少网络传输:由于在覆盖索引中可以存储所有查询所需的列,因此可以减少数据的网络传输次数,从而提高查询的性能。
- 可以降低系统开销:在高压力的数据库系统中,使用覆盖索引可以减少系统开销,从而提高系统的可靠性和可维护性。
覆盖索引的缺点包括:
- 需要更多的内存:覆盖索引需要存储查询所需的所有列,因此需要更多的内存来存储索引。在大型数据库系统中,这可能会成为一项挑战。
- 会使索引变得庞大:当索引中包含了许多列时,它们可能会使索引变得非常庞大,从而影响查询性能,并且可能会占用大量的磁盘空间。
- 只有在查询中包含了索引列时才能使用:只有当查询中包含了所有的索引列时才能使用覆盖索引。如果查询中包含了其他列,DBMS仍然需要访问实际的数据行,并且无法使用覆盖索引提高查询性能。
索引下推
核心思想:减少回表次数。
一般情况下索引下推是MYSQL优化自动处理,不需要程序员干预。
索引下推,是基于多列索引的,根据查询条件在索引层进行筛选,这样就减少了回表次数。
假设有以下表结构:
表名:users
id | name | age | city |
---|---|---|---|
1 | John | 25 | New York |
2 | Alice | 30 | London |
3 | Bob | 40 | Paris |
4 | Olivia | 35 | Berlin |
5 | Michael | 28 | Sydney |
现在我们创建了一个多列索引:(索引下推通常是基于多列索引的。)
ALTER TABLE users ADD INDEX idx_name_city_age (name, city, age);
假设我们要查询年龄大于30岁,并且所在城市是"London"的用户,假设只给age字段添加了索引,它就不会使用索引下推。传统的查询优化器会将所有满足年龄大于30岁的记录读入内存,然后再根据城市进行筛选。
使用索引下推优化后,在索引范围扫描的过程中,优化器会判断只有在城市列为"London"的情况下,才会将满足年龄大于30岁的记录加载到内存中。这样就可以避免不必要的IO和数据传输,提高查询性能。
具体的查询语句可以是:
SELECT * FROM users WHERE age > 30 AND city = 'London';
在执行这个查询时,优化器会使用索引下推技术,先根据索引范围扫描找到所有满足条件的记录,然后再回到原数据表中获取完整的行数据,最终返回结果。
单列索引(单一索引)
单一索引是指将表的某一字段作为索引。对表数据进行查询时,用作为索引的表字段作为筛选条件,查询最快。
复合索引(组合索引)
对数据库表中多个列进行索引创建。
索引的优缺点(面试可能会问)
优点:
- 提高查询性能:通过创建索引,可以大大减少数据库查询的数据量,从而提升查询的速度。
- 加速排序:当查询需要按照某个字段进行排序时,索引可以加速排序的过程,提高排序的效率。
- 减少磁盘IO:索引可以减少磁盘IO的次数,这对于磁盘读写速度较低的场景,尤其重要。
缺点:
- 占据额外的存储空间:索引需要占据额外的存储空间,特别是在大型数据库系统中,索引可能占据较大的空间。
- 增删改操作的性能损耗:每次对数据表进行插入、更新、删除等操作时,需要更新索引,会导致操作的性能降低。
- 资源消耗较大:索引需要占用内存和CPU资源,特别是在大规模并发访问的情况下,可能对系统的性能产生影响。
何时用索引
在以下情况下建议使用索引:
- 频繁执行查询操作的字段:如果这些字段经常被查询,使用索引可以提高查询的性能,减少查询的时间。
- 大表:当表的数据量较大时,使用索引可以快速定位到所需的数据,提高查询效率。
- 需要排序或者分组的字段:在对字段进行排序或者分组操作时,索引可以减少排序或者分组的时间。
- 外键关联的字段:在进行表之间的关联查询时,使用索引可以加快关联查询的速度。
在以下情况下不建议使用索引:
- 频繁执行更新操作的表:如果表经常被更新数据,使用索引可能会降低更新操作的性能,因为每次更新都需要维护索引。
- 小表:对于数据量较小的表,使用索引可能并不会带来明显的性能提升,反而会占用额外的存储空间。
- 对于唯一性很差的字段,一般不建议添加索引。当一个字段的唯一性很差时,查询操作基本上需要扫描整个表的大部分数据。如果为这样的字段创建索引,索引的大小可能会比数据本身还大,导致索引的存储空间占用过高,同时也会导致查询操作的性能下降。
总之,索引需要根据具体情况进行使用和权衡,需要考虑到表的大小、查询频率、更新频率以及业务需求等因素。