1 MySQL索引
MySQL
索引分类:普通索引,唯一索引,主键索引
1.1 添加索引
1.1.1 普通索引
创建表时添加索引:
create table table_name (属性名 数据类型,...,属性名 数据类型,
index |key [索引名] (属性名1 [(长度)] [asc|desc],...,
属性名n [(长度)] [asc|desc])
);
参数说明
长度是指定索引长度
asc|desc指定索引是升序还是降序
添加表普通索引:
create index idx_name on 表名(列名1 [(长度)] [asc|desc] ,...,
列名n [(长度)] [asc|desc]);
通过alter table 创建索引
alter table table_name
add index |key [索引名] (属性名 [(长度)] [asc|desc]
,...,
属性名n [(长度)] [asc|desc])
唯一索引:unique index
,把添加普通索引的index
替换为unique index
即可
全文索引:fulltext index
,把添加普通索引的index
替换为fulltext index
即可
1.1.2 索引中长度参数
使用 索引长度
的原因:
- 减少索引大小:完整的字符串索引可能会非常大,通过索引前缀可以显著减少索引大小。
- 提高查询性能:较小的索引在内存中占用更少的空间,查找速度更快。
- 避免不必要的索引:对于长字符串,通常前几个字符就可以区分大部分记录,索引前缀足以提高查询效率。
注意事项
- 适用场景:
索引长度
只适用于字符串类型的列,例如CHAR、VARCHAR、TEXT
类型。 - 前缀长度的选择:前缀长度的选择需要权衡索引大小和查询效率,一般来说,前缀应足够长以确保索引的选择性。
1.2 删除索引
命令如下:
drop index index_name on 表名;
或者如下:
alter table 表名 drop index index_name;
1.3 查看索引执行计划
explain
或desc
这个命令来查看一个这些SQL
语句的执行计划,就是为了分析耗时,是否走索引
查看SQL
是否使用索引,前面加上explain
或desc
即可,在Oracle
中是explain plan for
命令查看索引执行计划,还得紧接着查询表才有结果select plan_table_output from TABLE(DBMS_XPLAN.DISPLAY('PLAN_TABLE'));
explain select * from emp where name = 'Jefabc'
expain出来的信息有10
列,分别是id、select_type、table、type、possible_keys、key、key_len、ref、rows、Extra
:
概要描述:
-
id
:选择标识符 -
select_type
:表示查询的类型。 -
table
:输出结果集的表 -
partitions
:匹配的分区 -
type
:表示表的连接类型 -
possible_keys
:表示查询时,可能使用的索引 -
key
:表示实际使用的索引 -
key_len
:索引字段的长度 -
ref:
列与索引的比较 -
rows
:扫描出的行数(估算的行数) -
filtered
:按表条件过滤的行百分比 -
Extra
:执行情况的描述和说明
type
:查询中使用了何种类型,结果值从最好到最坏:system>const>eq_ref>ref>fulltext>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>all
一般来说,得保证查询至少达到range
级别,最好能到达ref
-
null
:MySQL
不访问任何表或索引,直接返回结果 -
system
:表只有一行记录(等于系统表),这是const
类型的特例,平时不会出现 -
const
:表示通过索引一次就能够找到,表示使用了主键或者唯一索引与常量值进行比较
-
eq_ref
:唯一性索引扫描,对于每个索引键,表示只有一条记录与之匹配,常见于主键或唯一索引扫描,通常使用在多表联查中
。比如,对两张表进行联查,关联条件是两张表的 user_id 相等,且 user_id 是唯一索引,那么使用EXPLAIN
进行执行计划查看的时候,type 就会显示 eq_ref。 -
ref
:非唯一性索引扫描,返回匹配某个单独值的所有行,返回单条记录,常出现在关联查询中
,虽然使用了索引,但该索引列的值并不唯一,有重复。这样即使使用索引快速查找到了第一条数据,仍然不能停止,要进行目标值附近的小范围扫描。但它的好处是它并不需要扫全表,因为索引是有序的,即便有重复值,也是在一个非常小的范围内扫描 -
range
:采用了索引范围扫描,一般在where
子句中使用< 、>、in、between
等关键词,只检索给定范围的行,属于范围查找。从这一级别开始,索引的作用会越来越明显,因此我们需要尽量让SQL
查询可以使用到range
这一级别及以上的type
访问方式 -
index
:虽然index
比all
快(index
是从索引中读取,all是从硬盘中读取),但是index
和all
差不多,只不过index
对索引表进行全扫描,这样做的好处是不再需要对数据进行排序,但是开销依然很大,所以,要尽量避免全表扫描和全索引扫描。 -
all
:遍历全表才能找到
Extra
:执行情况的描述和说明
-
Using filesort
:MySQL
需要额外的一次传递,以找出如何按排序顺序检索行。通过根据联接类型浏览所有行并为所有匹配WHERE
子句的行保存排序关键字和行的指针来完成排序。然后关键字被排序,并按排序顺序检索行。 -
Using temporary
:使用了临时表保存中间结果,性能特别差,需要重点优化 -
Using index
:表示相应的select
操作中使用了覆盖索引(Coveing Index
),避免访问了表的数据行,效率不错,如果同时出现using where
,意味着无法直接通过索引查找来查询到符合条件的数据。 -
Using where
:表明使用了where
进行过滤 -
impossible where
:如果where
子句的值总是false
,不能用来获取任何元组 -
Using join buffer
:使用了连接缓存 -
Using index condition
:MySQL5.6
之后新增的ICP,using index condtion
就是使用了ICP(索引下推),在存储引擎层进行数据过滤,而不是在服务层过滤,利用索引现有的数据减少回表的数据。 -
select table optimized away
:在没有group by
子句的情况下,基于索引优化min/max
操作或者对于myisam
存储引擎优化count(*)
操作,不必等到执行阶段再进行计算
1.4 索引分类
MySQL
索引种类有:普通索引、唯一索引(主键索引、唯一索引)、联合索引、全文索引、空间索引
MySQL
中索引类型 :
-
FULLTEXT
:即为全文索引,目前只有MyISAM
引擎支持。其可以在CREATE TABLE ,ALTER TABLE ,CREATE INDEX
使用,不过目前只有CHAR、VARCHAR ,TEXT
列上可以创建全文索引。 -
HASH
:由于HASH
的唯一(几乎100%的唯一)及类似键值对的形式,很适合作为索引。HASH
索引可以一次定位,不需要像树形索引那样逐层查找,因此具有极高的效率。但是,这种高效是有条件的,即只在“=”和“in”
条件下高效,对于范围查询、排序及组合索引仍然效率不高。
只有Memory存储
引擎显式支持哈希索引 -
BTREE
:BTREE
索引就是一种将索引值按一定的算法,存入一个树形的数据结构中(二叉树),每次查询都是从树的入口root
开始,依次遍历node
,获取leaf
。这是MySQL里默认和最常用的索引类型。 -
RTREE
:RTREE
在MySQL
很少使用,仅支持geometry
数据类型,支持该类型的存储引擎只有MyISAM、BDb、InnoDb、NDb、Archive
几种。相对于BTREE
,RTREE
的优势在于范围查找
1.5 全文索引
1.5 全文索引
1.5.1 简介
全文检索通常使用倒排索引(inverted index
)来实现,倒排索引同 B+Tree 一样,也是一种索引结构。它在辅助表中存储了单词与单词自身在一个或多个文档中所在位置之间的映射。全文索引只能在 MyISAM
和InnoDB(5.6以后的版本)
引擎 的表上使用,并且只能用于创建 char,varchar,text
类型的列。
1.5.2 操作
1.5.2.1 创建全文索引(FULLTEXT INDEX)
创建表的同时创建全文索引
CREATE TABLE `article` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`title` varchar(255) DEFAULT NULL COMMENT '标题',
`body` text COMMENT '内容',
PRIMARY KEY (`id`),
FULLTEXT KEY `body` (`body`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
通过 ALTER TABLE
的方式来添加
ALTER TABLE `student`
ADD FULLTEXT INDEX ft_stu_name (`name`) #ft_stu_name是索引名,可以随便起
# 或者
ALTER TABLE `student`
ADD FULLTEXT ft_stu_name (`name`)
直接通过CREATE INDEX
的方式
CREATE FULLTEXT INDEX ft_email_name ON `student` (`name`)
# 也可以在创建索引的时候指定索引的长度
CREATE FULLTEXT INDEX ft_email_name ON `student` (`name` (20))
1.5.2.2 删除全文索引
直接使用 DROP INDEX
(注意:没有 DROP FULLTEXT INDEX
这种用法)
格式:DROP INDEX full_idx_name ON db_name.table_name;
例子:DROP INDEX full_idx_name ON tommy.girl ;
使用 ALTER TABLE
的方式
格式:ALTER TABLE db_name.table_name DROP INDEX full_idx_name;
例子:ALTER TABLE tommy.girl DROP INDEX ft_email_abcd;
1.5.3 使用全文索引
跟普通索引稍有不同,使用全文索引的格式: MATCH (columnName) AGAINST (‘string’)
全文搜索使用 MATCH() AGAINST()
语法进行,其中,MATCH()
采用逗号
分隔的列表,命名要搜索的列
,AGAINST()
接收一个要搜索的字符串,以及一个要执行的搜索类型的可选修饰符。
全文检索分为三种类型:自然语言搜索
、布尔搜索
、查询扩展搜索
,下面将对各种查询模式进行介绍。
1.5.3.1 Natural Language
1.5.3.1.1 使用
自然语言搜索
将搜索字符串解释为自然人类语言中的短语,MATCH()
默认采用 Natural Language
模式,其表示查询带有指定关键字的文档。
SELECT * FROM `student` WHERE MATCH(`name`) AGAINST('聪')
当查询多列数据时:建议在此多列数据上创建一个联合的全文索引,否则使用不了索引的。
SELECT * FROM `student` WHERE MATCH(`name`,`address`) AGAINST('聪 广东')
使用全文索引需要注意的是:(基本单位是词
)
分词,全文索引以词为基础的,MySQL
默认的分词是所有非字母和数字的特殊符号都是分词符
相关性的计算依据以下四个条件:
- word 是否在文档中出现
- word 在文档中出现的次数
- word 在索引列中的数量
- 多少个文档包含该 word
1.5.3.1.2 MySQL相关变量
对于 InnoDB 存储引擎的全文检索,还需要考虑以下的因素:
- 查询的 word 在 stopword 列中,忽略该字符串的查询
- 查询的 word 的字符长度是否在区间 [innodb_ft_min_token_size,innodb_ft_max_token_size] 内
如果词在 stopword 中,则不对该词进行查询,如对 'for' 这个词进行查询,结果如下所示:
SELECT
*,
MATCH ( title, body ) against ( 'for' ) AS Relevance
FROM
fts_articles;
可以看到,for
虽然在文档 2,4 中出现,但由于其是 stopword
,故其相关性为 0。
参数 innodb_ft_min_token_size
和 innodb_ft_max_token_size
控制 InnoDB 引擎查询字符的长度。
当长度小于 innodb_ft_min_token_size
或者长度大于 innodb_ft_max_token_size
时,会忽略该词的搜索。
在 InnoDB 引擎中,参数 innodb_ft_min_token_size
的默认值是 3,innodb_ft_max_token_size
的默认值是 84。
必须通过修改MySQL
的配置文件来完成。通常修改最小搜索长度的值为2,首先打开MySQL的配置文件
在 [mysqld]的下面追加
innodb_ft_min_token_size=2
ft_min_word_len=2
ngram_token_size=2
使用命令:mysql> SHOW VARIABLES LIKE 'ft%';
ft就是FullText的简写
变量名字 | 变量值 | 变量说明 |
---|---|---|
ft_boolean_syntax | + -><()~*:""&| | 改变IN BOOLEAN MODE的查询字符,不用重新启动MySQL也不用重建索引 |
ft_min_word_len | 4 | 最短的索引字符串,默认值为4,(通常改为1)修改后必须重建索引文件。重新建立索引命令:repair table tablename quick |
ft_max_word_len | 84 | 最长的索引字符串,默认值为84,修改后必须重建索引文件 |
ft_query_expansion_limit | 20 | 查询括展时取最相关的几个值用作二次查询 |
ft_stopword_file | (built-IN) | 全文索引的过滤词文件,具体可以参考:MySQL全文检索中不进行全文索引默认过滤词 |
使用命令:show variables like "%ngram%"
变量名字 | 变量值 | 变量说明 |
---|---|---|
ngram_token_size | 2 | ngram解析器令牌长度即against()中字符串切分的最小字符长度 |
特别注意:50%
的门坎限制(当查询结果很多,几乎所有记录都有,或者极少的数据,都有可能会返回非所期望的结果):可用IN BOOLEAN MODE
即可以避开50%的限制。
此时使用全文索引的格式就变成了:
SELECT * FROM `student` WHERE MATCH(`name`) AGAINST('聪' IN BOOLEAN MODE)
注意
:修改完参数以后,一定要修复下索引,不然参数不会生效。
两种修复方式,可以使用下面的命令修复
- repair命令修复:
repair table test quick;
- 直接删掉重新建立索引
1.5.3.2 Boolean
1.5.3.2.1 简介
布尔搜索
使用特殊查询语言的规则来解释搜索字符串,该字符串包含要搜索的词,它还可以包含指定要求的运算符,例如匹配行中必须存在或不存在某个词,或者它的权重应高于或低于通常情况。
例如,下面的语句要求查询有字符串"Pease"但没有"hot"的文档,其中+和-分别表示单词必须存在,或者一定不存在。
select * from fts_test where MATCH(content) AGAINST('+Pease -hot' IN BOOLEAN MODE);
Boolean 全文检索支持的类型包括:
-
+
:表示该 word 必须存在,用在词的前面,表示一定要包含该词,并且必须在开始位置
+Apple
匹配:Apple123, “tommy, Apple” -
-
:表示该 word 必须不存在,不包含该词,所以不能只用-yoursql
这样是查不到任何row的,必须搭配其他语法使用
MATCH (girl_name) AGAINST (‘-林志玲 +张筱雨’)
匹配到: 所有不包含林志玲,但包含张筱雨的记录 -
空
(no operator
):表示该word
是可选的,但是如果出现,其相关性会更高,(也就是默认情况),表示可选的,包含该词的顺序较高
apple banana 找至少包含上面词中的一个的记录行;- +apple +juice 两个词均在被包含;
- +apple macintosh 包含词 “apple”,但是如果同时包含 “macintosh”,它的排列将更高一些;
- +apple -macintosh 包含 “apple” 但不包含 “macintosh”。
-
@distance
:表示查询的多个单词之间的距离是否在distance
之内,distance
的单位是字节,这种全文检索的查询也称为Proximity Search
(接近搜索),如MATCH(context) AGAINST('"Pease hot"@30' IN BOOLEAN MODE)
语句表示字符串 Pease 和 hot 之间的距离需在 30 字节内 -
>
:提高该字的相关性,查询的结果会排在比较靠前的位置 -
<
:降低相关性,查询的结果会排在比较靠后的位置 -
~
:表示允许出现该单词,但出现时相关性为负,表示拥有该字会降低相关性,但不像-
将之排除,只是排在较后面
比如:+apple ~macintosh
: 先匹配apple
,但如果同时包含macintosh
,就排名会靠后。 -
" "
: 表示短语,双引号内作为整体不能拆词
比如:"tommy huang"
可以匹配tommy huang xxxxx
但是不能匹配tommy is huang
-
*
:通配符,只能接在词后面
,表示以该单词开头的单词,如lik*
,表示可以是 lik,like,likes -
( )
:可以通过括号来使用字条件
比如:+aaa +(>bbb <ccc)
: 找到有aaa
和bbb
和ccc
,aaa
和bbb
,或者aaa
和ccc
(因为bbb,ccc前面没有+,所以表示可有可无),然后 aaa&bbb > aaa&bbb&ccc > aaa&ccc
1.5.3.2.2 使用讲解
先不使用 ><
select * from article where match(body) against('明天晴天 ' in boolean mode);
可以看到完全匹配的排的比较靠前。
单独使用 >
select * from article where match(body) against('明天晴天 > 好好学习 ' in boolean mode);
单独使用 <
select * from article where match(body) against('明天晴天 < 出去放风筝' in boolean mode);
同时使用><
select * from article where match(body) against('明天晴天 > 阴天了吧 <好好学习 > 喝奶茶去 < 出去放风筝' in boolean mode);
demo3:@
SELECT
*
FROM
`fts_articles`
WHERE
MATCH ( title, body ) AGAINST ( '"DB2 IBM"@3' IN BOOLEAN MODE );
上述语句,代表 "DB2" ,"IBM"两个词之间的距离在 3 字节之内。
1.5.3.3 Query Expansion
查询扩展搜索
是对自然语言搜索的修改,这种查询通常在查询的关键词太短,用户需要 implied knowledge
(隐含知识)时进行。
例如,对于单词 database
的查询,用户可能希望查询的不仅仅是包含 database
的文档,可能还指那些包含 MySQL、Oracle、RDBMS
的单词,而这时可以使用 Query Expansion
模式来开启全文检索的 implied knowledge
。
通过在查询语句中添加 WITH QUERY EXPANSION / IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION
可以开启 blind query expansion
(又称为 automatic relevance feedback)。
该查询分为两个阶段:
- 根据搜索的单词进行全文索引查询
- 根据第一阶段产生的分词再进行一次全文检索的查询
看看 Query Expansion 是如何使用的。
-- 创建索引
create FULLTEXT INDEX title_body_index on fts_articles(title,body);
-- 使用 Natural Language 模式查询
SELECT
*
FROM
`fts_articles`
WHERE
MATCH(title,body) AGAINST('database');
使用 Query Expansion 前查询结果如下:
-- 当使用 Query Expansion 模式查询
SELECT
*
FROM
`fts_articles`
WHERE
MATCH(title,body) AGAINST('database' WITH QUERY expansion);
使用 Query Expansion 后查询结果如下:
由于 Query Expansion
的全文检索可能带来许多非相关性的查询,因此在使用时,用户可能需要非常谨慎。
1.6 索引优缺点
索引优点:
- 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
- 可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
- 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
- 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
- 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
索引缺点:
- 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
- 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度
-
时间方面
:创建索引和维护索引要耗费时间
,具体地,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执行效率; -
空间方面
:索引需要占物理空间,索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大
1.7 创建索引条件
适合建立索引列:
- 在经常需要搜索的列上,可以加快搜索的速度;
- 在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
- 在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
- 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
- 在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
- 在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。
不适合建立索引列:
- 对于那些在查询中很少使用或者参考的列不应该创建索引。这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
- 对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
- 对于那些定义为
text
,image
和bit
数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。 - 当修改性能远远大于检索性能时,不应该创建索引。这是因为,
修改性能
和检索性能
是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。
2 MySQL虚拟表
虚拟表,顾名思义,就是实际上并不存在(物理上不存在)
,但是逻辑上存在的表。这样说很抽象,还是看一些实际的例子吧。
在mysql中,存在三种虚拟表:临时表
、内存表
和视图
2.1 临时表
2.1.1 定义和操作
临时表
:是建立在系统临时文件夹中的表,如果使用得当,完全可以像普通表一样进行各种操作。 临时表的数据和表结构都储存在内存之中,退出时,其所占的空间会自动被释放。
创建临时表
定义字段
CREATE TEMPORARY TABLE tmp_table (
name VARCHAR(10) NOT NULL,
value INTEGER NOT NULL)
直接将查询结果导入临时表
CREATE TEMPORARY TABLE tmp_table SELECT * FROM table_name
查询临时表
select * from tmp_table
删除临时表
drop table tmp_table
2.1.2 临时表的应用
当工作在十分大的表上运行时,在实际操作中你可能会需要运行很多的相关查询,来获的一个大量数据的小的子集。较好的办法,不是对整个表运行这些查询,而是让MySQL每次找出所需的少数记录,将记录选择到一个临时表,然后对这些表运行查询。
- 当某一个SQL语句关联的表在2张及以上,并且和一些小表关联。可以采用将大表进行分拆并且得到比较小的结果集合存放在临时表中。
- 程序执行过程中可能需要存放一些临时的数据,这些数据在整个程序的会话过程中都需要用的等等。
- 临时表默认的是
MyISAM
,但是可以修改。 - 可以把一些经常访问的数据放到临时表中,这样访问时会快一些,因为数据是在服务器内存中,另外每次查询的时候,数据库都需要生成一些临时数据在临时表里
2.1.3 临时表使用注意事项
- 临时表只在当前连接可见,当这个连接关闭的时候,会自动drop。这就意味着你可以在两个不同的连接里使用相同的临时表名,并且相互不会冲突,或者使用已经存在的表,但不是临时表的表名。(当这个临时表存在的时候,存在的表被隐藏了,如果临时表被drop,存在的表就可见了)。
- 临时表只能用在 memory,myisam,merge,或者innodb引擎。
- 临时表不支持
mysql cluster
(簇)。 - 在同一个
query
语句中,你只能查找一次临时表。例如:下面的就不可用
SELECT * FROM temp_table, temp_table AS t2;
ERROR 1137: Can't reopen table: 'temp_table'
如果在一个存储函数里,你用不同的别名查找一个临时表多次,或者在这个存储函数里用不同的语句查找,这个错误都会发生。
-
show tables
语句不会列举临时表,但是会列出内存表。 - 不能用
rename
来重命名一个临时表。但是,你可以alter table
代替
mysql>ALTER TABLE orig_name RENAME new_name;
2.2 内存表
2.2.1 定义和操作
内存表
:表结构建在磁盘里,数据在内存里 ,当停止服务后,表中的数据丢失,而表的结构不会丢失
。内存表也可以被看作是临时表的一种。
内存表的建立:
CREATE TEMPORARY TABLE tmp_table (
name VARCHAR(10) NOT NULL,
value INTEGER NOT NULL
) TYPE = HEAP
注意: TYPE = HEAP必须要有
2.2.2 内存表的应用
内存表使用哈希散列索引把数据保存在内存中,因此具有极快的速度,适合缓存中小型数据库。
-
heap
对所有用户的连接是可见的,这使得它非常适合做缓存。 - 一旦服务器重启,所有
heap
表数据丢失,但是heap
表结构仍然存在,因为heap
表结构是存放在实际数据库路径下的,不会自动删除。重启之后,heap
将被清空,这时候对heap的查询结果都是空的。 - 如果
heap
是复制的某数据表(创建普通用户表这些也会丢失),则复制之后所有主键、索引、自增等格式将不复存在,需要重新添加主键和索引,如果需要的话。 - 对于重启造成的数据丢失,有以下的解决办法:
- 在任何查询之前,执行一次简单的查询,判断
heap
表是否存在数据,如果不存在,则把数据重新写入,或者DROP表重新复制某张表。这需要多做一次查询。不过可以写成include文件,在需要用该heap表的页面随时调用,比较方便。 - 对于需要该
heap
表的页面,在该页面第一次且仅在第一次查询该表时,对数据集结果进行判断,如果结果为空,则需要重新写入数据。这样可以节省一次查询。 - 更好的办法是在
mysql
每次重新启动时自动写入数据到heap
,但是需要配置服务器,过程比较复杂,通用性受到限制。
- 在任何查询之前,执行一次简单的查询,判断
2.2.3 内存表的注意事项
-
heap
不允许使用xxxTEXT
和xxxBLOB
数据类型;只允许使用=和<=>操作符来搜索记录(不允 许& amp; lt;、>、<=或>=);只允许对非空数据列进行索引(not null)。
注:操作符<=>
说明:NULL-safe equal,这个操作符和“=”操作符执行相同的比较操作,不过在两个操作码均为NULL时,其所得值为1而不为NULL,而当一个操作码为NULL时,其所得值为0而不为NULL。 - 内存表可以通过
max_heap_table_size = 2048M
来加大使用的内存。 - 内存表必须使用
memory
存储引擎
2.3 视图
视图的工作机制:当调用视图的时候,才会执行视图中的sql,进行取数据操作。视图的内容没有存储,而是在视图被引用的时候才派生出数据。这样不会占用空间,由于是即时引用,视图的内容总是与真实表的内容是一致的。
视图这样设计有什么好处,节省空间,内容是总是一致的话,那么我们不需要维护视图的内容,维护好真实表的内容,就可以保证视图的完整性了
2.3.1 视图操作SQL
视图创建:
create view view_name as 查询语句;
示例例子
create view view_name as select * from TableName;
视图查看:
show table status [from db_name] [like '条件'];
此处db_name是数据库名字
查看视图定义信息
show create view view_name;
查看视图设计信息
desc | describe view_name;
查看所有视图信息
SELECT * FROM information_schema.`VIEWS`
视图修改:
create or replace view view_name as 查询语句;
alter view view_name as select * from OtherTable;
视图删除:
drop view view_name;
2.3.2 视图和临时表的区别
- 视图只是一条预编译的
SQL
语句,并不保存实际数据,临时表是保存在tempdb
中的实际的表 - 物理空间的分配不一样,视图不分配空间, 临时表会分配空间
- 视图是一个快照,是一个虚表,临时表是客观存在的表类型对象
Create TEMPORARY table
,它们的结构一个是表、一个快照。可以把视图像象成联合表的快捷方式
2.3.3 修改视图和原表关系
如果是单表无论新增还是修改,改了视图会影响原表,改了原表会影响视图,如果是多表联合查询视图,一次只能改一个表的数据,如果多了就报错如下提示:
Can not modify more than one base table through a join view 'test.test_view'
3 游标
3.1 定义
游标使用步骤:
- 声明游标
DECLARE cursor_name CURSOR FOR select查询语句;
- 打开游标
OPEN cursor_name
- 使用游标
FETCH cursor_name INTO var_name [,var_name] …
- 关闭游标
CLOSE cursor_name
3.2 例子
3.2.1 案例一
DROP PROCEDURE IF EXISTS emplayee_count;
DELIMITER $
#创建存储过程
CREATE PROCEDURE emplayee_count (OUT NUM INTEGER)
BEGIN
#声明变量
DECLARE emplayee_sal INTEGER;
DECLARE flag INTEGER;
#声明游标
DECLARE cursor_emplayee
CURSOR FOR SELECT sal FROM t_employee;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag = 1;
#设置结束标志
SET flag=0;SET NUM=0;‘
#打开游标
OPEN cursor_emplayee;
#遍历游标指向的结果集
FETCH cursor_emplayee INTO emplayee_sal;
WHILE flag<>1 DO
IF emplayee_sal >999 THEN
SET num=num+1;
END IF;
FETCH cursor_emplayee INTO emplayee_sal;
END WHILE;
#关闭游标
CLOSE cursor_emplayee;
END$
DELIMITER ;
调用执行
set @n=0; --定义变量
call emplayee_count(@n); -- 传参
select @n; -- 查询参
3.2.2 案例二
DELIMITER //
CREATE PROCEDURE processRecords()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE id INT;
DECLARE name VARCHAR(255);
-- 声明游标
DECLARE cur CURSOR FOR SELECT id, name FROM your_table;
-- 定义异常处理器
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-- 打开游标
OPEN cur;
-- 循环遍历记录
read_loop: LOOP
FETCH cur INTO id, name; -- 从游标中读取一行记录
IF done THEN -- 如果没有更多记录,则退出循环
LEAVE read_loop;
END IF;
-- 在这里可以对每一行记录进行操作
-- 例如,可以进行条件判断、计算等逻辑处理
END LOOP;
-- 关闭游标
CLOSE cur;
END //
DELIMITER ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
是MySQL
存储过程中用于定义异常处理器的语句。
在这个语句中,CONTINUE HANDLER
是异常处理器的类型,它用于处理在游标操作中遇到的异常情况。NOT FOUND
是一种特定的异常类型,表示在游标操作中没有更多的记录可供读取。
该语句的作用是当游标达到结果集末尾时,将变量done
设置为TRUE
,以便退出循环。在存储过程中使用这个异常处理器可以确保在遍历记录时能够正确地处理结果集为空的情况。
通过定义这个异常处理器,在使用游标进行记录遍历时,当游标达到结果集末尾时会触发该异常,并执行相应的处理逻辑。这样可以保证在遍历记录时能够正确地判断是否还有更多记录可供读取
注意
:要先定义游标,再定义HANDLER
;声明的变量不要和数据库中字段同名,不然fetch..into..
会获取不到 into
后的值