1.子查询
可以将子查询放在许多的 SQL 子句中,包括:
• WHERE 子句
• HAVING 子句
• FROM 子句
使用子查询的原则
• 子查询放在圆括号中。
• 将子查询放在比较条件的右边。
• 在单行子查询中用单行运算符,在多行子查询中用多行运算符。
示例 :谁的薪水比 Oldlu 高
select em.last_name,em.salary from employees em where em.salary > (select e.salary from employees e where e.last_name = 'Oldlu')
单行子查询
示例 :查询 Oldlu 的同事,但是不包含他自己。
select empl.last_name from employees empl where empl.department_id = (select e.department_id from employees e where e.last_name = 'Oldlu')
and empl.last_name <> 'Oldlu'
多行子查询
示例:查找各部门收入为部门最低的那些雇员。显示他们的名字,薪水以及部门 ID。
select em.last_name,em.salary,em.department_id from employees em where em.salary in(select min(e.salary) from employees e group by e.department_id)
2.MySQL 中的正则表达式
正则表达式
• MySQL 中允许使用正则表达式定义字符串的搜索条件,性能要高于 like。
• MySQL 中的正则表达式可以对整数类型或者字符类型检索。
• 使用 REGEXP 关键字表示正则匹配。
• 默认忽略大小写,如果要区分大小写,使用 BINARY 关键字
正则表达式的模式及其含义
“^”符号
^在正则表达式中表示开始
语法
查询以 x 开头的数据(忽略大小写)
SELECT 列名 FROM 表名 WHERE 列名 REGEXP '^x';
示例 :查询雇员表中名字是以 k 开头的雇员名字与薪水。
select last_name,salary from employees where last_name REGEXP binary '^K'
“$”符号
语法
查询以 x 结尾的数据(忽略大小写)
SELECT 列名 FROM 表名 WHERE 列名 REGEXP 'x$';
示例 :查询雇员表中名字是以 n 结尾的雇员名字与薪水。
select last_name,salary from employees where last_name REGEXP binary 'n$'
“.”符号
语法
英文的点,它匹配任何一个字符,包括回车、换行等。
SELECT 列名 FROM 表名 WHERE 列名 REGEXP 'x.';
示例 :查询雇员表中名字含有 o 的雇员的姓名与薪水。
select last_name,salary from employees where last_name REGEXP 'o.'
“*”符号
语法
“*”:星号匹配 0 个或多个字符,在它之前必须有内容。
“+”符号
语法
"+":加号匹配 1 个或多个字符,在它之前也必须有内容。
SELECT 列名 FROM 表名 WHERE 列名 REGEXP 'x+';-匹配大于 1 个的任意字符
“?”符号
语法
“?”:问号匹配 0 次或 1 次。
SELECT 列名 FROM 表名 WHERE 列名 REGEXP 'x?';-匹配 0 个或 1 个字符
“|”符号
语法
“|”:表示或者含义
SELECT 列名 FROM 表名 WHERE 列名 REGEXP 'abc|bcd';-匹配包含 abc 或 bcd
示例 :查询雇员表中名字含有 ke 或者 lu 的雇员的名字与薪水。
select last_name,salary from employees where last_name REGEXP 'ke|lu'
“[a-z]”
语法
“[a-z]”:字符范围
“^[....]”:以什么字符开头的
“[^....]”:匹配不包含在[]的字符
SELECT 列名 FROM 表名 WHERE 列名 REGEXP '[a-z]';-匹配内容包含 a-z 范围的数据
示例一 :查询雇员表中名字包含 x、y、z 字符的雇员的名字和薪水。
select last_name,salary from employees where last_name REGEXP '[x-z]'
示例二:查询雇员名字是 t、f 开头的雇员名字与薪水。
select last_name,salary from employees where last_name REGEXP '^[t|f]'
示例三 :查询雇员的名字与薪水,不包含 oldlu。
select last_name,salary from employees where last_name REGEXP '[^oldlu]'
“{n}” 语法
“{n}”:固定次数。
select * from student where name REGEXP 's{2}';--匹配以 s 连续出现 2 次的所有数据
示例一 :查询雇员名字含有连续两个 e 的雇员的姓名与薪水
select last_name,salary from employees where last_name REGEXP 'e{2}'
示例二 :查询名字中含有两个 o 的雇员的名字与薪水。
select last_name,salary from employees where last_name REGEXP 'o.{2}'
“{n,m}” 语法
“{n,m}”:范围次数。
select * from student where name REGEXP '^s{2,5}';--匹配以 s 开头且重复 2 到 5 次的所有数据
示例 :查询雇员名字中包含 1 个或者两个 o 的雇员姓名与薪水。
select last_name,salary from employees where last_name REGEXP 'o.{1,2}'
3.MySQL 中的其他对象:索引
MySQL 索引的建立对于 MySQL 的高效运行是很重要的,索引可以大大提高 MySQL的检索速度。
MySQL 中的索引类型
• 普通索引
• 唯一索引
• 主键索引
• 组合索引
• 全文索引
--普通索引
是最基本的索引,它没有任何限制。
在创建索引时,可以指定索引长度。length 为可选参数,表示索引的长度,只有字符串类型的字段才能指定索引长度,如果是 BLOB 和 TEXT 类型,必须指定 length。
创建索引时需要注意:
如果指定单列索引长度,length 必须小于这个字段所允许的最大字符个数。
---查询索引:
SHOW INDEX FROM table_name
--直接创建索引
语法结构:CREATE INDEX index_name ON table(column(length))
示例 :为 emp3 表中的 name 创建一个索引,索引名为 emp3_name_index
create index emp3_name_index ON emp3(name)
---修改表添加索引
语法结构:ALTER TABLE table_name ADD INDEX index_name (column(length))
示例 :修改 emp3 表,为 addrees 列添加索引,索引名为 emp3_address_index
alter table emp3 add index emp3_address_index(address)
--创建表时指定索引列
语法结构:
CREATE TABLE `table`
(
COLUMN TYPE ,
PRIMARY KEY (`id`),
INDEX index_name (column(length))
)
示例
创建 emp4 表,包含 emp_id,name,address 列,同时为 name 列创建索引。索引名为emp4_name_index
create table emp4(emp_id int primary key auto_increment,name varchar(30),address varchar(50),index emp4_name_index(name))
--删除索引
语法结构:DROP INDEX index_name ON table
示例 :删除 mep3 表中索引名为 emp3_address_index 的索引
drop index emp3_address_index on emp3
--唯一索引
唯一索引与普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。它有以下几种创建方式:
---创建唯一索引
语法结构:CREATE UNIQUE INDEX indexName ON table(column(length))
示例 :为 emp 表中的 name 创建一个唯一索引,索引名为 emp_name_index
create unique index emp_name_index on emp(name)
修改表添加唯一索引
语法结构:ALTER TABLE table_name ADD UNIQUE indexName (column(length))
示例 :修改 emp 表,为 salary 列添加唯一索引,索引名为 emp_salary_index
alter table emp add unique emp_salary_index(salary)
--创建表时指定唯一索引
CREATE TABLE `table` (
COLUMN TYPE ,
PRIMARY KEY (`id`),
UNIQUE index_name (column(length))
)
示例
创建 emp5 表,包含 emp_id,name,address 列,同时为 name 列创建唯一索引。索引名为emp5_name_index
create table emp5(emp_id int primary key ,name varchar(30),address varchar(30),unique emp5_name_index(name))
--主键索引
主键索引是一种特殊的唯一索引,一个表只能有一个主键,不允许有空值。一般是在建表的时候同时创建主键索引。
---修改表添加主键索引
语法结构:ALTER TABLE 表名 ADD PRIMARY KEY(列名)
示例 :修改 emp 表为 employee_id 添加主键索引
alter table emp add primary key(employee_id)
--创建表时指定主键索引
CREATE TABLE `table` (
COLUMN TYPE ,
PRIMARY KEY(column)
)
示例 :创建 emp6 表,包含 emp_id,name,address 列,同时为 emp_id 列创建主键索引
create table emp6(employee_id int primary key auto_increment,name varchar(20),address varchar(50))
--组合索引
组合索引是指使用多个字段创建的索引,只有在查询条件中使用了创建索引时的第一个
字段,索引才会被使用(最左前缀原则)。
---最左前缀原则
就是最左优先。
如:我们使用表中的 name,address,salary 创建组合索引,那么想要组合索引生效,
我们只能使用如下组合:
name/address/salary
name/address
name/
如果使用 addrees/salary 或者是 salary 则索引不会生效。
--修改添加组合索引
语法结构:ALTER TABLE table_name ADD INDEX index_name (column(length),column(length))
示例 :修改 emp6 表,为 name,address 列创建组合索引
alter table emp6 add index emp6_index_n_a(name,address)
--创建表时创建组合索引
CREATE TABLE `table` (
COLUMN TYPE ,
INDEX index_name (column(length),column(length))
)
示例 :创建 emp7 表,包含 emp_id,name,address 列,同时为 name,address 列创建组合索引。
create table emp7(emp_id int primary key auto_increment ,name varchar(20),address varchar(30),index emp7_index_n_a(name,address))
--全文索引
全文索引(FULLTEXT INDEX)主要用来查找文本中的关键字,而不是直接与索引中的值相比较。FULLTEXT 索引跟其它索引大不相同,它更像是一个搜索引擎,而不是简单的 where语句的参数匹配。FULLTEXT 索引配合 match against 操作使用,而不是一般的 where 语句
加 like。
全文索引可以从 CHAR、VARCHAR 或 TEXT 列中作为 CREATE TABLE 语句的一部分被创建,或是随后使用 ALTER TABLE 添加。不过切记对于大容量的数据表,生成全文索引是一个非常消耗时间非常消耗硬盘空间的做法。
--修改添加全文索引
ALTER TABLE table_name ADD FULLTEXT index_content(content)
示例一 :修改 emp7 表添加 content 列类型为 TEXT
alter table emp7 add COLUMN content text;
示例二 :修改 emp7 表,为 content 列创建全文索引
alter table emp7 add fulltext emp7_content_fullindex(content)
--创建表时创建全文索引
CREATE TABLE `table` (
COLUMN TYPE ,
FULLTEXT index_name (column)
)
示例
创 建 emp8 表 包 含 emp_id 列 , content 列 该 列 类 型 为 text , 并 为 该 列 添 加 名 为 emp8_content_fulltext 的全文索引
create table emp8(emp_id int primary key auto_increment,content text,fulltext emp8_content_fullindex(content))
--删除全文索引
语法结构:
DROP INDEX index_name ON table
ALTER TABLE table_name DROP INDEX index_name
示例 :删除 emp8 表中名为 emp8_content_full 的索引。
drop index emp8_content_fullindex on emp8
--使用全文索引
全 文 索 引 的 使 用 与 其 他 索 引 不 同 。 在 查 询 语 句 中 需 要 使 用 match(column) against(‘content’) 来检索数据。
---全文解析器
全文索引中基本单位是”词”。分词,全文索引是以词为基础的,MySQL 默认的分词是所有非字母和数字的特殊符号都是分词符。在检索数据时我们给定的检索条件也是词。MySQL 中默认的全文解析器不支持中文分词。如果数据含有中文需要更换全文解析器 NGRAM。
---使用全文索引
语法结构:SELECT 投影列 FROM 表名 WHERE MATCH(全文索引列名) AGAINST(‘搜索内容’)
示例一 :修改 emp8 表,为 content 列创建名为 emp8_content_full 的全文索引
alter table emp8 add fulltext emp8_content_full(content)
示例二 :向 emp8 表中插入一条数据 content 的值为”hello,bjsxt”
insert into emp8 values(default ,'hello bjsxt')
示例三 :查询 emp8 表中内容包含 bjsxt 的数据。
select * from emp8 where match(content) AGAINST('bjsxt')
--更换全文解析器
在创建全文索引时可以指定 ngram 解析器
语法结构:
ALTER TABLE table_name ADD FULLTEXT index_content(content) WITH PARSER NGRAM
示例一 :删除 emp8 表中的 emp8_content_full 全文索引
drop index emp8_content_full on emp8
示例二 :修改 emp8 表,为 content 列添加名称为 emp8_content_full 的全文索引,并指定 ngram 全文解析器。
alter table emp8 add fulltext emp8_content_full(content) with parser ngram
4.MySQL 中的用户管理
MySQL 是一个多用户的数据库系统,按权限,用户可以分为两种:root 用户,超级管
理员,和由 root 用户创建的普通用户。
---MySQL 创建用户
CREATE USER username IDENTIFIED BY 'password';
---查看用户
SELECT USER,NOST FROM USER(该表位于 mysql 库中)
示例 :创建一个 u_sxt 的用户,并查看创建是否成功。
select user,host from mysql.user
create user u_sxt IDENTIFIED by 'sxt'
--分配权限
新用户创建完后是无法登陆的,需要分配权限。
GRANT 权限 ON 数据库.表 TO 用户名@登录主机 IDENTIFIED BY "密码"
GRANT ALL PRIVILEGES ON *.* TO 'username'@'localhost' IDENTIFIED BY 'password'
登陆主机:
% 匹配所有主机
localhost localhost 不会被解析成 IP 地址,直接通过 UNIXsocket 连接
127.0.0.1 会通过 TCP/IP 协议连接,并且只能在本机访问;
::1 ::1 就是兼容支持 ipv6 的,表示同 ipv4 的 127.0.0.1
--权限列表
ALTER: 修改表和索引。
CREATE: 创建数据库和表。
DELETE: 删除表中已有的记录。
DROP: 删除数据库和表。
INDEX: 创建或删除索引。
INSERT: 向表中插入新行。
SELECT: 检索表中的记录。
UPDATE: 修改现存表记录。
FILE: 读或写服务器上的文件。
PROCESS: 查看服务器中执行的线程信息或杀死线程。
RELOAD: 重载授权表或清空日志、主机缓存或表缓存。
SHUTDOWN: 关闭服务器。
ALL: 所有权限,ALL PRIVILEGES 同义词。
USAGE: 特殊的 "无权限" 权限
示例 :为 u_sxt 用户分配只能查询 bjsxt 库中的 employees 表,并且只能在本机登陆的权限。
grant select ON bjsxt.employees to 'u_sxt'@'localhost' IDENTIFIED by 'sxt'
---刷新权限
每当调整权限后,通常需要执行以下语句刷新权限
FLUSH PRIVILEGES
---删除用户
DROP USER username@localhost
示例 :删除 u_sxt 用户
drop user 'u_sxt'@'localhost'
--通过 Navicat 工具管理用户
---创建用户
分配权限
5.MySQL 分页查询
MySQL 分页查询原则
• 在 MySQL 数据库中使用 LIMIT 子句进行分页查询。
• MySQL 分页中开始位置为 0。
• 分页子句在查询语句的最后侧。
--LIMIT 子句
语法格式
SELECT 投影列 FROM 表名 WHERE 条件 ORDER BY LIMIT 开始位置,查询数量。
示例 :查询雇员表中所有数据按 id 排序,实现分页查询,每次返回两条结果。
select * from employees order by employees_id limit 0,2
--LIMIT OFFSET 子句
语法格式
SELECT 投影列 FROM 表名 WHERE 条件 ORDER BY LIMIT 查询数量 OFFSET 开始位置。
示例 :查询雇员表中所有数据按 id 排序,使用 LIMIT OFFSET 实现分页查询,每次返回两条结果。
select * from employees order by employees_id limit 2 offset 4
6.MySQL 中的执行计划
--MySQL 执行计划
在 MySQL 中可以通过 explain 关键字模拟优化器执行 SQL 语句,从而知道 MySQL 是如何处理 SQL 语句的。
--MySQL 整个查询执行过程
• 客户端向 MySQL 服务器发送一条查询请求
• 服务器首先检查查询缓存,如果命中缓存,则立刻返回存储在缓存中的结果。否则进
入下一阶段
• 服务器进行 SQL 解析、预处理、再由优化器生成对应的执行计划
• MySQL 根据执行计划,调用存储引擎的 API 来执行查询
• 将结果返回给客户端,同时缓存查询结果
--启动执行计划
EXPLAIN SELECT 投影列 FROM 表名 WHERE 条件
--EXPLAIN 列的解释
--ID
查询执行顺序:
id 值相同时表示从上向下执行
id 值相同被视为一组
如果是子查询,id 值会递增,id 值越高,优先级越高
--select_type
simple:表示查询中不包含子查询或者 union
primary:当查询中包含任何复杂的子部分,最外层的查询被标记成 primary
derived:在 from 的列表中包含的子查询被标记成 derived
subquery:在 select 或 where 列表中包含了子查询,则子查询被标记成 subquery
union:两个 select 查询时前一个标记为 PRIMARY,后一个标记为 UNION。union 出现
在 from 从句子查询中,外层 select 标记为 PIRMARY,union 中第一个查询为 DERIVED,第二个子查询标记为 UNION
unionresult:从 union 表获取结果的 select 被标记成 union result 。
--table
显示这一行的数据是关于哪张表的。
--type
这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为 system、const、 eq_reg、ref、range、index 和 ALL。
system:表中只有一行数据。属于 const 的特例。如果物理表中就一行数据为 ALL
const :查询结果最多有一个匹配行。因为只有一行,所以可以被视为常量。const 查询速度非常快,因为只读一次。一般情况下把主键或唯一索引作为唯一条件的查询都是 const
eq_ref:查询时查询外键表全部数据。且只能查询主键列或关联列。且外键表中外键列中数据不能有重复数据,且这些数据都必须在主键表中有对应数据(主键表中数据可以有没有用到的)
ref:相比 eq_ref,不对外键列有强制要求,里面的数据可以重复,只要出现重复的数据取值就是 ref。也可能是索引查询。
range:把这个列当作条件只检索其中一个范围。常见 where 从句中出现 between、<、in 等。
主要应用在具有索引的列中
index:这个连接类型对前面的表中的每一个记录联合进行完全扫描(比 ALL 更好,因为索引一般小于表数据)。
ALL:这个连接类型对于前面的每一个记录联合进行完全扫描,这一般比较糟糕,应该尽量避免。
--possible_keys
查询条件字段涉及到的索引,可能没有使用。
--Key
实际使用的索引。如果为 NULL,则没有使用索引。
--key_len
表示索引中使用的字节数,查询中使用的索引的长度(最大可能长度),并非实际使用长度,理论上长度越短越好。key_len 是根据表定义计算而得的,不是通过表内检索出的。
--ref
显示索引的哪一列被使用了,如果可能的话,是一个常量 const。
--rows
根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数。
--Fitered
显示了通过条件过滤出的行数的百分比估计值。
--extra
MYSQL 如何解析查询的额外信息。
Distinct:MySQL 发现第 1 个匹配行后,停止为当前的行组合搜索更多的行。
Not exists:MySQL 能够对查询进行 LEFT JOIN 优化,发现 1 个匹配 LEFT JOIN 标准的行后,不再为前面的的行组合在该表内检查更多的行。
range checked for each record (index map: #):MySQL 没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。
Using filesort:MySQL 需要额外的一次传递,以找出如何按排序顺序检索行。
Using index:从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。
Using temporary:为了解决查询,MySQL 需要创建一个临时表来容纳结果。
Using where:WHERE 子句用于限制哪一个行匹配下一个表或发送到客户。
Using sort_union(...), Using union(...), Using intersect(...): 这 些 函 数 说 明 如 何 为
index_merge 联接类型合并索引扫描。
Using index for group-by:类似于访问表的 Using index 方式,Using index for group-by 表示
MySQL 发现了一个索引,可以用来查 询 GROUP BY 或 DISTINCT 查询的所有列,而不要额外搜索硬盘访问实际的表。
7.MySQL 数据库存储引擎介绍
查看 MySQL 数据库中的数据库存储引擎
ISAM(Indexed Sequential Access Method)
ISAM 是一个定义明确且历经时间考验的数据表格管理方法,它在设计之时就考虑到数据库被查询的次数要远大于更新的次数。
注意:使用 ISAM 时必须经常备份所有实时数据。
MyISAM
MyISAM 是 MySQL 的 ISAM 扩展格式和缺省的数据库引擎。除了提供 ISAM 里所没有的索引和字段管理的大量功能,MyISAM 还使用一种表格锁定的机制,来优化多个并发的读写操作,其代价是你需要经常运行 OPTIMIZE TABLE 命令,来恢复被更新机制所浪费的空间。
注意:MyISAM 引擎使用时必须经常使用 Optimize Table 命令清理空间;必须经常备份所有实时数据。工具有用来修复数据库文件的 MyISAMCHK 工具和用来恢复浪费空间的MyISAMPACK 工具。
如果使用该数据库引擎,会生成三个文件:
.frm:表结构信息
.MYD:数据文件
.MYI:表的索引信息
InnoDB
InnoDB 数据库引擎都是造就 MySQL 灵活性的技术的直接产品,这项技术就是 MYSQL++API。
innodb 与 myisam 区别
1. InnoDB 支持事务,MyISAM 不支持,对于 InnoDB 每一条 SQL 语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条 SQL 语言放在 begin 和 commit 之间,组成一个事务;
2. InnoDB 支持外键,而 MyISAM 不支持。对一个包含外键的 InnoDB 表转为 MYISAM会失败;
3. InnoDB 是聚集索引,数据文件是和索引绑在一起的,必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。而 MyISAM 是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。
4. InnoDB 不保存表的具体行数,执行 select count(*) from table 时需要全表扫描。而MyISAM 用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快;
5. Innodb 不支持全文索引,而 MyISAM 支持全文索引,查询效率上 MyISAM 要高;(在MySQL5.7 版本中已经支持全文索引)
如何选择:
1. 是否要支持事务,如果要请选择 innodb,如果不需要可以考虑 MyISAM
2. 如果表中绝大多数都只是读查询,可以考虑 MyISAM,如果既有读写也挺频繁,请使用 InnoDB。
3. 系统奔溃后,MyISAM 恢复起来更困难,能否接受;
4. MySQL5.5 版本开始 Innodb 已经成为 Mysql 的默认引擎(之前是 MyISAM),说明其优势是有目共睹的,如果你不知道用什么,那就用 InnoDB,至少不会差。
修改数据库级引擎
修改 MySQL 的 my.ini 配置文件
C:ProgramDataMySQLMySQL Server 5.7
default-storage-engine=数据库引擎名称
重启 MySQL
修改表级存储引擎
ALTER TBALE tableName engine=InnoDB
查询表的存储引擎
show create table table_name;
8.理解数据库设计的三大范式
数据库设计范式, 范式有什么作用?
数据库设计对数据的存储性能,还有开发人员对数据的操作都有莫大的关系。所以建立科学的,规范的的数据库是需要满足一些规范的来优化数据数据存储方式。在关系型数据库中这些规范就可以称为范式。
设计关系型数据库时,遵从不同的规范要求,设计出合理的关系型数据库。这些规范被称作范式。越高的范式数据库的 冗余度就越低。
数据库设计范式分类:
数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴德斯科范式(BCNF)、第四范式(4NF)和第五范式(5NF)。
第一范式
第一范式*(确保每列保持原子性)
第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库满足第一范式。
第一范式的合理遵循需要根据系统给的实际需求来确定。
第二范式
第二范式(确保表中的每列都和主键相关)
第二范式在第一范式的基础上更进一层,第二范式需要确保数据库表中每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。
第三范式
第三范式(确保每列都和主键列直接相关,而不是间接相关)
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。