From 741410287b867696cfc594446341c56a2812422a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A2=853?= <12071605+yangmei3@user.noreply.gitee.com> Date: Thu, 19 Oct 2023 05:20:05 +0000 Subject: [PATCH] 20231019 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 杨梅3 <> --- ...42\345\274\225\344\275\234\344\270\232.md" | 57 +++ ...42\345\274\225\347\254\224\350\256\260.md" | 472 ++++++++++++++++++ ...17\346\234\272\347\224\237\346\210\220.md" | 32 ++ 3 files changed, 561 insertions(+) create mode 100644 "27 \346\235\250\346\242\205/\347\264\242\345\274\225\344\275\234\344\270\232.md" create mode 100644 "27 \346\235\250\346\242\205/\347\264\242\345\274\225\347\254\224\350\256\260.md" create mode 100644 "27 \346\235\250\346\242\205/\351\232\217\346\234\272\347\224\237\346\210\220.md" diff --git "a/27 \346\235\250\346\242\205/\347\264\242\345\274\225\344\275\234\344\270\232.md" "b/27 \346\235\250\346\242\205/\347\264\242\345\274\225\344\275\234\344\270\232.md" new file mode 100644 index 0000000..1a57653 --- /dev/null +++ "b/27 \346\235\250\346\242\205/\347\264\242\345\274\225\344\275\234\344\270\232.md" @@ -0,0 +1,57 @@ +```mysql +create table tb_user( + id int primary key auto_increment comment '主键', + name varchar(50) not null comment '用户名', + phone varchar(11) not null comment '手机号', + email varchar(100) comment '邮箱', + profession varchar(11) comment '专业', + age tinyint unsigned comment '年龄', + gender char(1) comment '性别 , 1: 男, 2: 女', + status char(1) comment '状态', + createtime datetime comment '创建时间' +) comment '系统用户表'; + + +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('吕布', '17799990000', 'lvbu666@163.com', '软件工程', 23, '1', '6', '2001-02-02 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('曹操', '17799990001', 'caocao666@qq.com', '通讯工程', 33, '1', '0', '2001-03-05 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('赵云', '17799990002', '17799990@139.com', '英语', 34, '1', '2', '2002-03-02 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('孙悟空', '17799990003', '17799990@sina.com', '工程造价', 54, '1', '0', '2001-07-02 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('花木兰', '17799990004', '19980729@sina.com', '软件工程', 23, '2', '1', '2001-04-22 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('大乔', '17799990005', 'daqiao666@sina.com', '舞蹈', 22, '2', '0', '2001-02-07 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('露娜', '17799990006', 'luna_love@sina.com', '应用数学', 24, '2', '0', '2001-02-08 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('程咬金', '17799990007', 'chengyaojin@163.com', '化工', 38, '1', '5', '2001-05-23 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('项羽', '17799990008', 'xiaoyu666@qq.com', '金属材料', 43, '1', '0', '2001-09-18 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('白起', '17799990009', 'baiqi666@sina.com', '机械工程及其自动化', 27, '1', '2', '2001-08-16 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('韩信', '17799990010', 'hanxin520@163.com', '无机非金属材料工程', 27, '1', '0', '2001-06-12 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('荆轲', '17799990011', 'jingke123@163.com', '会计', 29, '1', '0', '2001-05-11 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('兰陵王', '17799990012', 'lanlinwang666@126.com', '工程造价', 44, '1', '1', '2001-04-09 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('狂铁', '17799990013', 'kuangtie@sina.com', '应用数学', 43, '1', '2', '2001-04-10 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('貂蝉', '17799990014', '84958948374@qq.com', '软件工程', 40, '2', '3', '2001-02-12 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('妲己', '17799990015', '2783238293@qq.com', '软件工程', 31, '2', '0', '2001-01-30 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('芈月', '17799990016', 'xiaomin2001@sina.com', '工业经济', 35, '2', '0', '2000-05-03 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('嬴政', '17799990017', '8839434342@qq.com', '化工', 38, '1', '1', '2001-08-08 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('狄仁杰', '17799990018', 'jujiamlm8166@163.com', '国际贸易', 30, '1', '0', '2007-03-12 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('安琪拉', '17799990019', 'jdodm1h@126.com', '城市规划', 51, '2', '0', '2001-08-15 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('典韦', '17799990020', 'ycaunanjian@163.com', '城市规划', 52, '1', '2', '2000-04-12 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('廉颇', '17799990021', 'lianpo321@126.com', '土木工程', 19, '1', '3', '2002-07-18 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('后羿', '17799990022', 'altycj2000@139.com', '城市园林', 20, '1', '0', '2002-03-10 00:00:00'); +INSERT INTO tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('姜子牙', '17799990023', '37483844@qq.com', '工程造价', 29, '1', '4', '2003-05-26 00:00:00'); + +-- 执行查询文件tb_user.sql,数据准备好了之后,完成如下需求: +-- +-- 1. name字段为姓名字段,该字段的值可能会重复,为该字段创建索引。 +desc tb_user; +create unique index uname_index on tb_user(name); +-- 2. phone手机号字段的值,是非空,且唯一的,为该字段创建唯一索引。 +create unique index phone_index on tb_user(phone); +show index from tb_user; +-- 3. 为profession、age、status创建联合索引。 +create index pro_age_sta on tb_user(profession,age,status); +show index from tb_user; +-- 4. 为email建立合适的索引来提升查询效率。 + +-- 5. 查看tb_user表的所有的索引数据 +show index from tb_user; + +``` + diff --git "a/27 \346\235\250\346\242\205/\347\264\242\345\274\225\347\254\224\350\256\260.md" "b/27 \346\235\250\346\242\205/\347\264\242\345\274\225\347\254\224\350\256\260.md" new file mode 100644 index 0000000..de68640 --- /dev/null +++ "b/27 \346\235\250\346\242\205/\347\264\242\345\274\225\347\254\224\350\256\260.md" @@ -0,0 +1,472 @@ +# 索引 + +-- 建立一个数据和表(id,name,phone,sex,hobby),想办法插入10万条数据, + +--案例 + +执行查询文件tb_user.sql,数据准备好了之后,完成如下需求: + +1. name字段为姓名字段,该字段的值可能会重复,为该字段创建索引。 +2. phone手机号字段的值,是非空,且唯一的,为该字段创建唯一索引。 +3. 为profession、age、status创建联合索引。 +4. 为email建立合适的索引来提升查询效率。 +5. 查看tb_user表的所有的索引数据。 + + + + + + + + + +#### 什么是索引? + +索引(index)是帮助MySQL**高效获取数据**的数据结构。 + +示例: + +假如我们要执行的SQL语句为 : select * from user where age = 45; + +![image-20230925225434449](索引.assets/image-20230925225434449.png) + +如果不使用索引,MySQL必须从第一条记录开始读完整个表,直到找出相关的行,表越大,查询数据所花费的时间就越多。 + + + +如果我们针对于这张表建立了索引,假设索引结构就是二叉树,那么也就意味着,会对age这个字段建立一个二叉树的索引结构。 + +![image-20230925225747156](索引.assets/image-20230925225747156.png) + +如果表中某个列拥有索引,MySQL能够快速到达一个位置去搜索数据文件,而不必查看所有数据,那么将会节省很大一部分时间。 + + + +## 索引的优点* 提升select 速度 90% + +提高数据检索的效率,**降低数据库的IO成本** + +通过索引列对数据进行排序,降低mysql对数据自动排序的成本,**降低CPU的消耗** + +#### 缺点(忽略不计): 降低了 INSERT、UPDATE、DELETE 速度 + +索引列也是要占用空间的。索引大大提高了查询效率,同时却也降低更新表的速度, + +如对表进行INSERT、UPDATE、DELETE时,需要对索引进行维护,效率降低。 + + + +## 索引的分类 + +单列索引:一个索引建立在一个列上,一张表可以拥有多个单列索引 + +- 普通索引:单纯地为了提高搜索效率 index +- 唯一索引:unique index,唯一索引只能够建立在数据不重复的列上 ,唯一约束 ,不能重复,可以null,有多个唯一索引 +- 主键索引:primary key唯一性、非空,主键约束 ,不能重复,也不能null,一个只能有一个主键 + +联合索引:可以同时为多个列创建一个索引 + +全文索引(了解) + + + +## 单列索引 + +#### 创建索引(普通索引) + +这是最基本的索引,它没有任何限制。它有以下几种创建方式: + +-- 方式一和二是给现成表加索引 + +方式一:直接在已有表中创建索引 + +```sql +create index 索引名 on 表名(列名) -- 直接删除索引 drop index 索引名 on 表名; 这种不能用来创建主键索引 +``` + +方式二:修改表结构追加普通索引 + +```sql +alter table 表名 add index 索引名(列名); -- 修改表结构删除索引 alter table 表名 drop index 索引名; +``` + +方式三:创建表的时候直接指定 + +```sql +create table 表名( + aaa int primary key, + bbb varchar(20), + index 索引名 (列名) -- 以这种模式定义的索引,可以不指定索引名称。 + primary key(列名) +); +``` + + + + + +#### 查看表的索引 + +```sql +show index from 表名; +``` + +可以查看到创建在表上的所有索引名称。 + + + +#### 删除索引 + +```sql +drop index 索引名 on 表名; +``` + +并且删除表时,会一并删除表上的全部索引。 + +```sql +alter table 表名 drop index 索引名; +``` + + + +#### 唯一索引:建立列的唯一约束时,会自动创建唯一的索引,索引名就是列名 + +它与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。它有以下几种创建方式 + +```mysql +create unique index 索引名 on 表名(列名); -- 创建普通索引的基础上。多了unique关键字 +``` + +​ 在已存在的表上追加唯一索引 + +```mysql +alter table 表名 add unique 索引名 (列名) +``` + +​ 创建表的时候直接指定 + +```mysql +create table tc_9( + aaa int primary key, + bbb varchar(20), + unique [INDEX] 索引名 (列名) -- 唯一索引,一定有索引名,index 可以省略 +); + +-- 唯一索引和唯一约束 语法还是 有些区别 +create table tc_9( + aaa int primary key, + bbb varchar(20), + tel char(11), -- unique not null, + unique (tel) -- unique(列名) -- 约束是没有 索引名 和 index 关键字的 +); +``` + +**删除唯一索引的方法与删除普通索引相同。** + + + + + + + + +#### 主键索引 与 index 关键字没有关系 + +主键索引:它是一种特殊的唯一索引,不允许有空值。一般是在建表的时候指定了主键,就会创建主键索引, CREATE INDEX不能用来创建主键索引,使用 ALTER TABLE来代替。 + +创建主键索引,就是创建主键约束 + +```sql +drop table if exists tc_10; +create table tc_10( + aaa int primary key, + bbb varchar(20), + ccc datetime +); +create table tc_10( + aaa int, + bbb varchar(20), + ccc datetime, + primary key(aaa) +); +create table tc_10( + aaa int, + bbb varchar(20), + ccc datetime +); +alter table tc_10 add primary key(aaa); +``` + + + +删除主键 + +可以使用 ALTER 命令删除主键: index + +```sql +alter table 表名 drop primary key; +``` + +删除主键时只需指定PRIMARY KEY,但在删除索引时,你必须知道索引名。而不能使用删除普通索引的方法来删除主键索引。 + +```sql +-- 这都是错误的。 +drop index PRIMARY on tc_10; +drop primary key on tc_10; +``` + + + +## 联合索引 + +```sql +create index 索引名 on 表名(列名1,列名2....) -- 普通的联合索引 +create unique index 索引名 on 表名(列名1,列名2....) -- 联合唯一索引 +``` + +*执行原则:最左前缀法则 + + + +#### 案例 + +执行查询文件tb_user.sql,数据准备好了之后,完成如下需求: + +1. name字段为姓名字段,该字段的值可能会重复,为该字段创建索引。 +2. phone手机号字段的值,是非空,且唯一的,为该字段创建唯一索引。 +3. 为profession、age、status创建联合索引。 +4. 为email建立合适的索引来提升查询效率。 +5. 查看tb_user表的所有的索引数据。 + + + + + +## 全文索引 中国 + +全文索引:FULLTEXT索引用于全文搜索,只能在char,varchar,text等中创建全文检索 + +最小搜索长度:3个字符 + +优点:比like快N倍 缺点:会出现精度问题 + + + +​ 创建全文索引 + +```sql +-- 创建表的适合添加全文索引 +create table t_article ( + id int primary key auto_increment , + title varchar(255) , + content varchar(1000) , + writing_date date -- , + -- fulltext (content) -- 创建全文检索 +); + +insert into t_article values(null,"Yesterday Once More","When I was young I listen to the radio",'2021-10-01'); +insert into t_article values(null,"Right Here Waiting","Oceans apart, day after day,and I slowly go insane",'2021-10-02'); +insert into t_article values(null,"My Heart Will Go On","every night in my dreams,i see you, i feel you",'2021-10-03'); +insert into t_article values(null,"Everything I Do","eLook into my eyes,You will see what you mean to me",'2021-10-04'); +insert into t_article values(null,"Called To Say I Love You","say love you no new year's day, to celebrate",'2021-10-05'); +insert into t_article values(null,"Nothing's Gonna Change My Love For You","if i had to live my life without you near me",'2021-10-06'); +insert into t_article values(null,"Everybody","We're gonna bring the flavor show U how.",'2021-10-07'); + +-- 修改表结构添加全文索引 +alter table t_article add fulltext index_content(content) + +-- 添加全文索引 +create fulltext index index_content on t_article(content); + +-- 使用全文索引 +select * from t_article where match(content) against('yo'); -- 没有结果 +select * from t_article where match(content) against('you'); -- 有结果 +select * from t_article where content like '%you%'; +``` + +​ 删除全文索引,与删除普通索引一致。 + +```sql +drop index index_content on t_article; +``` + + + +## explain 执行计划 + +可用于查看某个查询语句的执行详细情况 + +语法: + +```sql +explain select ... from ...... +``` + + + +Explain 执行计划中各个字段的含义: + +| 字段 | 含义 | +| ------------ | ------------------------------------------------------------ | +| id | select查询的序列号,表示查询中执行select子句或者是操作表的顺序(id相同,执行顺序从上到下;id不同,值越大,越先执行)。 | +| select_type | 表示 SELECT 的类型,常见的取值有 SIMPLE(简单表,即不使用表连接或者子查询)、PRIMARY(主查询,即外层的查询)、UNION(UNION 中的第二个或者后面的查询语句)、SUBQUERY(SELECT/WHERE之后包含了子查询)等 | +| type | 表示连接类型,性能由好到差的连接类型为NULL、system、const、eq_ref、ref、range、 index、all | +| possible_key | 显示可能应用在这张表上的索引,一个或多个 | +| key | 实际使用的索引,如果为NULL,则没有使用索引 | +| key_len | 表示索引中使用的字节数, 该值为索引字段最大可能长度,并非实际使用长度,在不损失精确性的前提下,长度越短越好 | +| rows | MySQL认为必须要执行查询的行数,在innodb引擎的表中,是一个估计值,可能并不总是准确的 | +| filtered | 表示返回结果的行数占需读取行数的百分比, filtered 的值越大越好 | + + + +## 索引的使用 + +#### 最左前缀法则(联合索引) + +如果使用了联合索引,要遵守最左前缀法则。 + +最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列。如果跳跃某一列,后面的字段索引失效。 + + + +案例: + +在 tb_user 表中,有一个联合索引,这个联合索引涉及到三个字段,顺序分别为:profession,age,status。 + +```sql +-- 观察key_len +explain select * from tb_user where profession = '软件工程' and age = 31 and status = '0'; +explain select * from tb_user where profession = '软件工程' and age = 31; +explain select * from tb_user where profession = '软件工程'; + +-- 违反法则 +explain select * from tb_user where age = 31 and status = '0'; +explain select * from tb_user where status = '0'; +explain select * from tb_user where profession = '软件工程' and status = '0'; + +-- 思考 +explain select * from tb_user where age = 31 and status = '0' and profession = '软件工程'; +``` + + + +#### 范围查询 + +```sql +explain select * from tb_user where profession = '软件工程' and age > 30 and status = '0'; + +-- 解决 +explain select * from tb_user where profession = '软件工程' and age >= 30 and status = '0'; +``` + + + +## 索引失效情况 + +#### 索引列运算 + +```sql +explain select * from tb_user where substring(phone,10,2) = '15'; +``` + +#### 字符串不加引号 + +```sql +explain select * from tb_user where profession = '软件工程' and age = 31 and status = '0'; +explain select * from tb_user where profession = '软件工程' and age = 31 and status = 0; --失效 + +explain select * from tb_user where phone = '17799990015'; +explain select * from tb_user where phone = 17799990015; --失效 +``` + + + +#### 模糊查询 + +```sql +explain select * from tb_user where profession like '软件%'; +explain select * from tb_user where profession like '%工程'; -- 失效 +explain select * from tb_user where profession like '%工%'; -- 失效 +``` + +#### or连接条件 and + +用or分割开的条件, 如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。 + +```sql +explain select * from tb_user where id = 10 or age = 23; +explain select * from tb_user where phone = '17799990017' or age = 23; + +--对age字段建立索引,再次执行 +create index idx_user_age on tb_user(age); +``` + +#### 数据分布影响 + +如果MySQL评估使用索引比全表更慢,则不使用索引。 + +```sql +-- 比较运算符范围查询 +select * from tb_user where phone >= '17799990005'; +select * from tb_user where phone >= '17799990015'; + +-- is null 与 is not null +explain select * from tb_user where profession is null; +explain select * from tb_user where profession is not null; +``` + + + +## SQL提示 + +```sql +select * from 表名 use index(索引名) where.... -- 建议 +select * from 表名 ignore index(索引名) where.... -- 忽略 +select * from 表名 force index(索引名) where.... -- 强制 +``` + + + +## 覆盖索引 + +尽量使用覆盖索引,减少select * 的使用。 + +那么什么是覆盖索引呢? 覆盖索引是指 查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到 。 + +```sql +explain select id, profession from tb_user where profession = '软件工程' and age = 31 and status = '0' ; +explain select id,profession,age,status from tb_user where profession = '软件工程' and age = 31 and status = '0' ; +explain select id,profession,age,status,name from tb_user where profession = '软件工程' and age = 31 and status = '0' ; +explain select * from tb_user where profession = '软件工程' and age = 31 and status = '0'; +``` + +| Extra | 含义 | +| ------------------------ | ------------------------------------------------------------ | +| Using where; Using Index | 查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据 | +| Using index condition | 查找使用了索引,但是需要回表查询数据 | + + + +## 单列索引与联合索引 + +到底是选单列索引还是联合索引? + +在业务场景中,如果存在多个查询条件,考虑针对于查询字段建立索引时,建议建立联合索引,而非单列索引。 + +-- + +## 索引设计原则 :索引方便查询的,影响插入。更新,删除 + +1). 数据量较大,且查询比较频繁的表。 100w + +2). 常作为查询条件(where)、排序(order by)、分组(group by)操作的字段。 + +3). 尽量选择区分度高的列,尽量建立唯一索引,区分度越高,使用索引的效率越高。 + +4). 如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。-- 分表 + +5). 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。 + +6). 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。 + +7). 如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引最有效地用于查询。 \ No newline at end of file diff --git "a/27 \346\235\250\346\242\205/\351\232\217\346\234\272\347\224\237\346\210\220.md" "b/27 \346\235\250\346\242\205/\351\232\217\346\234\272\347\224\237\346\210\220.md" new file mode 100644 index 0000000..4c2eb13 --- /dev/null +++ "b/27 \346\235\250\346\242\205/\351\232\217\346\234\272\347\224\237\346\210\220.md" @@ -0,0 +1,32 @@ +```mys +create database Apple charset utf8; +use Apple; +create table student( + id int primary key auto_increment,-- 主键 + name varchar(50) not null,-- 用户姓名 + sex char(1) comment '性别, 1: 男, 2: 女', + phone varchar(15) not null, + hobby varchar(20) not null +); + +-- 建立一个数据和表(id,name,phone,sex,hobby),想办法插入10万条数据, +delimiter // +create procedure Y(in num int) + begin + declare i int default 1; + declare name1 varchar(1); + declare name2 varchar(1); + declare fullname varchar(3); + declare tel varchar(15); + declare love varchar(10); + while i<= do + set name1=substring('杨李白赵王周孙郑吴秦许沈魏何朱唐钟程',floor(1+8*rand()),1); + set name2=substring('瑞雪茹静婷湘百言燕秋伟乔蕊芮佳嘉巧思',floor(1+8*rand()),1); + if round(rand())=0 then + set fullname = concat(name1,name2); + end if; + set tel = floor() + end // +delimiter ; +``` + -- Gitee