本文内容主要参考自《MySQL DBA 修炼之道》书中的第三章,算是原书的实践与补充。
MySQL 5.7 版本安装路径为 C:\Program Files\MySQL\MySQL Server 5.7\bin,默认不会添加环境变量,需要自行添加。
MySQL中变量可以分为用户变量和系统变量。
用户变量与连接有关,一个客户端定义的变量不能被其他客户端看到或使用。当客户端退出时,该客户端连接的所有变量将自动释放。
用户变量的形式为 @var_name,设置用户变量的一个途径是执行 SET 语句,语法如下:
set @var_name=var_value[, @var_name=var_value]...
MySQL服务器维护着两种系统变量:全局变量和会话变量。
全局变量会影响MySQL服务的整体运行方式,会话变量影响客户端连接的操作。
全局变量在MySQL启动的时候由服务器自动将它们初始化为默认值,这些默认值可以通过更改 my.ini 这个文件来更改,或者在命令行中对指定的选项进行更改。服务器启动后,可以通过 SET GLOBAL var_name 语句动态修改。
注意:
服务器为每个连接的客户端维护一系列的会话变量,在连接时使用相应全局变量的当前值对客户端的会话变量进行初始化。每个客户端可以修改自己的会话变量,通过 SET SESSION var_name 语句更改。
可以使用下面的语法来设置或者检索全局变量或会话变量,使用 sort_buffer_size 作为示例变量名。
对于整型数据,MySQL支持在类型后面的小括号内指定显示宽度,默认为 int(11)
。一般配合 zerofill
使用,当位数不够的时候会补零。当然,如果位数超了,也不会截断或报错,直接显示原来的。
对于 char
和 varchar
两种类型,后面也可以加上括号,比如 char(11)
和 varchar(11)
,对于MySQL5.0.3版本之后:
char(11)
代表长度固定为11个字符,如果不足会在后面添加空格,取出来的时候需要 trim()
去掉多余的空格。varchar(11)
代表可以最多存储11个字符,无论中英文都可以存11个。不足就按照实际的字符数,不填充。计算具体存放的字节数,需要考虑字符集,每个字符占用的字节数,同时 varchar
还有2个额外字节记录长度。无论怎样,char的字节数不能超过255字节,varchar
不能超过65535字节。
MySQL提供了一个练习所用的数据库 employees。下载地址:employees_db-full-1.0.6.tar.bz2
默认导入数据是InnoDB引擎,如果需要其他引擎,可以修改 employees.sql 文件,取消相关注释。并且如果是MySQL 5.7版本将 storage_engine
修改为 default_storage_engine
。
set storage_engine = InnoDB;
-- set storage_engine = MyISAM;
-- set storage_engine = Falcon;
-- set storage_engine = PBXT;
-- set storage_engine = Maria;
修改成:
set default_storage_engine = InnoDB;
-- set default_storage_engine = MyISAM;
-- set default_storage_engine = Falcon;
-- set default_storage_engine = PBXT;
-- set default_storage_engine = Maria;
select CONCAT('storage engine: ', @@default_storage_engine) as INFO;
导入 employees.sql 进数据库。
mysql -u root -p1234 -t < employees.sql
employees 数据库的 ER 关系图如下,利用 Navicat for MySQL 软件生成。
连接 MySQL Server。
mysql -h 127.0.0.1 -P 3306 -u root -p1234
连接成功,通过输入 quit
或者 exit;
进行退出。
查询当前 MySQL Server 的版本以及当前时间。
select version(), current_date, now();
创建一个数据库,名为 test。
create database test;
显示所有的数据库,使用刚刚创建的 test 数据库。
show databases;
use test;
查看当前正在使用的数据库,列出其中包含的所有的表。
select database();
show tables;
创建查看删除表:利用 CREATE TABLE 创建表格,利用 DESC 语句可以验证创建的表结构信息,通过 DROP TABLE 则可以删除表。
修改表:主要利用 ALTER TABLE 修改表的结构。
创建索引:使用 CREATE INDEX 语句创建索引。
删除索引:使用 DROP INDEX 语句删除索引。
修改字符集和排序规则
alter table lookup change name name varchar(10) character set latin1 collate latin1_bin;
增:INSERT 语句。
新增一条数据:
insert into table_name (列1,列2,列3) values (值1,值2,值3);
新增多条:
insert into table_name (列1,列2,列3) values (值1,值2,值3),(值4,值5,值6);
删:DELETE 语句。
单表删除:
delete from table_name [where 条件];
多表连接删除:
delete table_name1[, table_name2...] from table_name1, table_name2... [where 条件];
改:UPDATE 语句。
update table_name set 列1=值1,列2=值2,列3=值3... [where 条件];
查:SELECT 语句。
~ 查询所有数据:
select * from table_name;
~ 查询指定列名指定数据:
select 列1,列2,列3 from table_name [where 条件];
~ SQL模式匹配:
SQL有两个通配符,下划线 “_” 匹配任意单个字符,“%” 匹配任意多个字符,包括 0 字符。模式匹配默认区分大小写,一般使用 LIKE 或者 NOT LIKE 这些比较操作符。
~ 逻辑操作符与或非 AND、OR、NOT :
select 列1,列2,列3 from table_name where 条件1 AND 条件2;
select 列1,列2,列3 from table_name where 条件1 OR 条件2;
select 列1,列2,列3 from table_name where NOT 条件1;
~ 范围操作符 IN 和 BETWEEN :
select 列1,列2,列3 from table_name where xxx in (条件1, 条件2, 条件3);
select 列1,列2,列3 from table_name where xxx between 条件1 and 条件2);
~ 限制获取记录数 LIMIT :
select * from table_name limit 起点 记录数;
~ 排序 ORDER BY :
select * from table_name order by 列名 asc;
select * from table_name order by 列名1, 列名2 desc limit 起点 记录数;
~ 数据计算:
使用 MySQL 的计算函数来进行相关计算。
~ 利用 DISTINCT 获取不重复的唯一值:
在 SQL 语句中利用 DISTINCT 相当于去重,相同的只会留下一个。
~ 聚集函数:
聚集函数包含 COUNT、MIN、MAX、AVG、SUM。
~ 分组统计 GROUP BY:
一般将分组语句与聚集函数一起使用,从而实现分组统计。不仅如此,还支持对多个列同时进行聚集计算。
select Max(a), Max(b), Max(c) from table_name where... group by d;
上面这个就是先以 d 字段进行分组,然后组内再选出利用聚集函数计算出的结果。
我们还可以在 GROUP BY 语句后面添加 HAVING 子句,并对聚集结果进行筛选。
~ 并集操作 UNION 和 UNION ALL :
对两个结果集进行合并,UNION 和 UNION ALL 都是对结果集合并, UNION 会去重而 UNION ALL 不会。一般情况下两个结果集并不会重复,所以为了性能能用 UNION ALL 就用 UNION ALL 。
合并的两个结果集也必须形式上一致,否则出错。
~ NULL 值
NULL 值的判断一般使用 IS NULL 或者 IS NOT NULL,不能使用上面的比较操作符 =,因为 NULL 是个特殊的值,表示这个值时未知或者没有定义的。
select * from table_name where 列名 is not null;
对于 GROUP BY 字句,两个 NULL 值可以认为是相等的。
对于 NULL 值的排序,NULL 认为是最小的。
MySQL利用连接 JOIN 来查询多个表数据。表连接的方式主要是通过循环拼接方式进行的,例如表 A 连接表 B,假设表 A 的记录数比表 B 少 (记录少的在内层循环),相当于:
for 记录b_j in B:
for 记录a_i in A:
拼接记录a_i和记录b_j
连接的表越多,循环的层数也越多,所以设计查询时要尽量减少连接表的个数。
一般有三种连接:内连接、左连接和右连接。左连接和右连接其实都是外连接,MySQL中左外连接与左连接,右外连接和右连接是同一个。
内连接可以进一步分为等值连接、自然连接和交叉连接。等值连接是比较常用的,自然连接一般应该避免使用,而交叉连接其实就相当于上面的演示代码思想。
我们简单的进行演示,使用 employees 数据库中的 departments 和 dept_manager 数据表。departments 中有 9 条数据,dept_manager 中有 24 条数据。
内连接使用 INNER JOIN 关键字。交叉连接其实就是两张表的笛卡尔积,如图交叉结果所示,departments 连接 dept_manager 表其实就是 dept_manager × departments (右表×左表),外层是24次循环,内层是9次循环。而等值连接相当于内外层循环添加了条件,条件通过 ON 关键字来实现。
for 记录b_j in B:
for 记录a_i in A:
if 条件1 and 条件2:
拼接记录a_i和记录b_j
左连接/左外连接用 LEFT JOIN 关键字来实现,右连接/右外连接用 RIGHT JOIN 关键字来实现。左连接的含义是指如果表 A 左连接表 B,那么最后连接的结果必然包含全部的左表 A,即使 B 中没有满足条件的,那么直接补充为 NULL。右连接含义相同,仅仅只是必然包含右表 B。一般都习惯使用左连接,因为 A LEFT JOIN B 相当于 B RIGHT JOIN A。外连接的内外层循环和记录数目无关,用代码描述 A LEFT JOIN B 其实是(A 外层循环,B 内层循环,A 是驱动表,B 是被驱动表):
for 记录a_j in A:
for 记录b_i in B:
if 条件1 and 条件2:
临时表 = 拼接记录a_i和记录b_j
if 临时表 不包含所有A记录:
临时表添加A记录中缺失的,B的那些字段值设为NULL
继续从上面的例子分析,我们先删除 dept_manager 表中所有 dept_no 为 d009 的记录。然后我们再次通过等值连接查看结果数变为 20,将 INNER JOIN 变为 LEFT JOIN,结果多出一条,多出的正是 dept_no 为 d009 的记录,而右表 dept_manager 中的字段属性都是 NULL。
当然,对于连接出的结果,我们可以继续使用 WHERE 来添加条件进行过滤,但是出于性能,一般条件都在 ON 中表示,因为 ON 的条件是在连接表循环的中间判断的,而 WHERE 则需要连接产生的大表结束后一一遍历判断,性能受到影响。
具体关于连接的过程可以参考:Mysql - JOIN 详解
子查询是指查询语句中嵌套着 SELECT 语句。例如:
select * table1 where column1 = (select column1 from table2);
select * table1 是外部查询,select column1 from table2 是子查询。MySQL 对于子查询的优化不佳,所以一般可以将子查询的语句改写为 JOIN 语句,因此一般建议使用 JOIN 的方式查询数据。
生产环境一般不推荐 select * 的通配符 *。
MySQL 查询执行的顺序是:
(7) SELECT
(8) DISTINCT <select_list>
(1) FROM <left_table>
(3) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) HAVING <having_condition>
(9) ORDER BY <order_by_condition>
(10) LIMIT <limit_number>
记忆口诀:从上连那组,有查问许仙
解释:从From上On连Join哪Where组GroupBy 有Having查Select唯 Distinct序OrderBy限Limit
不喜勿喷