一、SQL结构化查询语言

SQL,英文全称Structured Query Language,中文意思是结构化查询语言。它是一种对关系数据库中的数据进行定义和操作的语言方法,是大多数关系数据库管理系统所支持的工业标准。

SQL分类:
DDL:数据定义语言,CREATE,ALTER,DROP。管理基础数据 <--运维熟练
DCL:数据控制语言,GRANT,REVOKE,COMMIT,ROLLBACK,用户授权,权限回收,数据提交回滚 <--运维要熟悉
DML:数据操作语言,SELECT,INSERT,DELETE,UPDATE,针对数据库里的表里的数据进行操作 <--开发熟练,运维了解

二、数据库基础管理

1、登录MySQL方法

(1)单实例MySQL登录的方法
mysql      #无密码登录方式
mysql -u root  #指定用户无密码登录
mysql -uroot -p  #标准dba命令行登录
mysql -uroot -p123456  #非脚本一般不这样使用,密码明文,容易泄露

(2)多实例防止密码泄露登录的方法
设置变量:HISTCONTROL=ignorespace
mysql -uroot -p123456 -S /data/3306/mysql.sock

(3)远程链接登录
mysql -uroot -p -h 192.168.56.11 -P3306
-h 指定ip地址,-P指定端口号

2、MySQL数据库安全策略介绍

(1)为root设置比较复杂的密码
(2)删除无用的mysql库内的用户账号,只留root@localhost
(3)删除默认的test数据库
(4)删除用户的时候,授权的权限尽量最小,允许访问的主机范围最小化
(4)针对mysql数据库的用户处理,还有更严格的做法,例如删除root用户,添加新的管理员用户

3、命令讲解

  • 创建数据库
(1) 语法:create database 库名;
(2)查看建表语句:show create database 库名;  
(3)创建指定字符集的数据库:create database 库名 default character set 字符 collate 校对方式;
(4)查看字符集:show character set;
(5)示例:create database test1; 
                    show create database test1;
                    create database test3 default character set utf8 collate utf8_general_ci;    #创建utf8格式
#如果编译的时候指定了特定的字符集,则以后创建对应字符集的数据库就不需要指定字符集

-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DEXTRA_CHARSETS=gbk,gb2312,utf8,ascii \
#提示:二进制软件包,安装的数据库字符集默认latinl
  • 连接数据库
(1)语法:use <dbname>
(2)示例:use test1;
  • 查看数据库
1)语法:select database();    #相当于pwd
                    select user();         #查看当前用户
                                        select version();   #查看当前版本
                                        select now();        #查看当前时间
  • 删除数据库

    (1)语法
    drop database <dbname>
    (2)示例
    drop database test1;
  • 删除数据库中指定用户
    (1)语法:drop user "user"@"主机域"2)要求:可以是单引号,也可以是双引号。但是不能不加。如果主机名中有大写字母的则 drop 删除不了,可以用 delete
    语句来删除 mysql.user 表中的用户。
    delete from mysql.user where user=’root’ and host=’oldboy’;
    flush privileges;
    (3)示例:
    drop user 'root'@'localhost';
    drop user 'system'@"localhost";
    drop user ''@"localhost";
  • 创建用户及授权
(1) 查看 GRANT 命令帮助获取创建用户并授权的例子:
MariaDB [test1]>  help grant;
CREATE USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass';
GRANT ALL ON db1.* TO 'jeffrey'@'localhost';
GRANT SELECT ON db2.invoice TO 'jeffrey'@'localhost';
GRANT USAGE ON *.* TO 'jeffrey'@'localhost' WITH MAX_QUERIES_PER_HOUR 90;

(2)普通授权方法:先 Creategrant
a、语法
CREATE USER 'username'@'主机域' IDENTIFIED BY 'mypass';
GRANT ALL ON dbname.* to 'username'@'localhost'

b、示例
create user 'user1'@'localhost' identified by '123456';
grant all on test1.* to 'user1'@'localhost';

(3)运维人员常用创建用户方法:使用 grant 命令在创建用户的同时进行授权
a、语法
GRANT ALL PRIVILEGES ON dbname.* to 'username'@'主机域' identified by 'password';

b、说明
GRANT ALL PRIVILEGES ON dbname.* to 'username'@'主机域' identified by 'password'
授权命令 对应权限 目标:库和表 用户名和客户端主机 用户密码
说明:上述命令是授权localhost主机上通过用户username管理dbname数据库的所有权限,密码为passwd,其中username,dbname,passwd可根据业务的情况修改
对于web连接用户授权尽量采用最小化原则,很多开源软件都是web界面安装,因此在安装期间除了select,insert,update,delete 4个权限外,还需要create,drop等比较危险的权限。

grant select,insert,update,create,drop on blog.* to blog@localhost identified by ‘123’

常规情况下授权select,insert,update,delete 4个权限即可,有的源软件,例如discuz,bbs还需要create,drop等比较危险的权限。生成数据库表后,要收回create,drop授权

(4)远程主机授权连接数据库
grant 命令的语法中主机域部分为授权访问数据库的客户端主机,可以用域名、 IP 或 IP 段来表示。远程主机
的授权方法有 2 种,具体如下:
a、方法一:百分号匹配法
grant all on *.* to test@'192.168.0.%' identified by '123456';
flush privileges;

b、方法二:子网掩码匹配法
grant all on *.* to test@'192.168.1.0/24' identified by '123456';
grant all on *.* to test@'192.168.1.0/255.255.255.0' identified by '123456';
flush privileges;
#如果是web连接数据库,尽量不要授权all,而是select,insert,update,delete

(5)查看权限
MariaDB [test1]> grant all on test1.* to test@'192.168.56.0/24' identified by '123456';
Query OK, 0 rows affected (0.00 sec)
MariaDB [test1]> show grants for test@'192.168.56.0/24';
+-------------------------------------------------------------------------------------------------------------------+
| Grants for test@192.168.56.0/24                                                                                   |
+-------------------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'test'@'192.168.56.0/24' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' |
| GRANT ALL PRIVILEGES ON `test1`.* TO 'test'@'192.168.56.0/24'                                                     |
+-------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

查看权限可以看出授权是分为 2 步:
第一步是授权可登陆 GRANT USAGE ON *.*。 USAGE 表示只有登陆权限。
第二步是授权可访问 ON `test1`.* TO 'test'@'192.168.56.0/24'

(6)权限回收
MariaDB [test1]> revoke insert on test1.* from test@'192.168.56.0/24';
Query OK, 0 rows affected (0.01 sec)

MariaDB [test1]> show grants for test@'192.168.56.0/24';
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Grants for test@192.168.56.0/24                                                                                                                                                                                                     |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'test'@'192.168.56.0/24' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9'                                                                                                                   |
| GRANT SELECT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `test1`.* TO 'test'@'192.168.56.0/24' |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

#MySQL 权限列表如下
SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY,
TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT,
TRIGGER

MySQL包含关系 :数据库服务器>数据库(多个实例)>多个库>多个表>多个字段行列(数据)
  • 创建表
1)语法:create table <表名>(
                   <字段名1><类型n>);
提示:其中create table是关键字,不能更改,但是大小写可以变化

(2)下面是人工写法设计的建表语句例子,表名student
create table student(
    id int(4) not null,
    name char(20) not null,
    age tinyint(2)  NOT NULL default '0',
    dept varchar(16)  default NULL
    );

(3)查看创建表的语句
mysql> show create table student;
create table student(       #create table表示创建表的固定关键字,student为表名
id int(4) not null,        #学号列,数字类型,长度为4,不能为空值
name char(20) not null,    #名字列,定长字符类型,长度20,不能为空
age tinyint(2)  NOT NULL default '0', #年龄列,很小的数字类型,长度为2,不能为空,默认为0值
dept varchar(16)  default NULL    #性别列,变长字符类型,长度16,默认为空。
ENGINE=lnnoDB DEFAULT CHARSET=latinl  #引擎和字符集,引擎默认为InnoDB,字符集,继承库的latinl
);

#需要注意的事:MySQL5.1和MySQL5.5 
环境的默认建表语句中的引擎的不同,如果希望控制引擎,就要在建表语句里显示的指定引擎建表;MySQL5.1以及默认引擎为MyISAM,MySQL5.5,以后默认引擎为InnoDB。
  • 生产场景案例:
    某sns产品生产正式建表语句
    use sns;
    set names gbk;
    CREATE TABLE `subject_comment_manager` (
    `subject_comment_manager_id` bigint(12) NOT NULL auto_increment COMMENT '主键',
    `subject_type` tinyint(2) NOT NULL COMMENT '素材类型',
    `subject_primary_key` varchar(255) NOT NULL COMMENT '素材的主键',
    `subject_title` varchar(255) NOT NULL COMMENT '素材的名称',
    `edit_user_nick` varchar(64) default NULL COMMENT '修改人',
    `edit_user_time` timestamp NULL default NULL COMMENT '修改时间',
    `edit_comment` varchar(255) default NULL COMMENT '修改的理由',
    `state` tinyint(1) NOT NULL default '1' COMMENT '0代表关闭,1代表正常',
    PRIMARY KEY  (`subject_comment_manager_id`),
    KEY `IDX_PRIMARYKEY` (`subject_primary_key`(32)), #<==括号内的32表示对前32个字符做前缀索引。
    KEY `IDX_SUBJECT_TITLE` (`subject_title`(32))
    KEY `index_nick_type` (`edit_user_nick`(32),`subject_type`)#<==联合索引,此行为新加的,用于给大家讲解的。实际表语句内没有此行。
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

4、索引

(1)为表的字段创建索引

索引就象书的目录一样,如果在字段上建立了索引,那么以索引为查询条件时可以加快查询数据的速度.
创建主键索引
查询数据库,按主键查询是最快的,每个表只有一个主键列,但是可以用多个普通索引列。主键列要求列的所有内容必须唯一,而普通索引不要求内容必须唯一
主键就类似我们在学校学习时的学号一样,班级内是唯一的,整个表的每一条记录的主键值在表内都是唯一的,用来唯一标识一条记录。

(1)建立主键索引的方法:
drop table student;
create table student(
id int(4) not null AUTO_INCREMENT,
name char(20) not null,
age tinyint(2)  NOT NULL default '0',
dept varchar(16)  default NULL,
primary key(id),
KEY index_name(name)
);

#提示: 
# primary key(id)<==主键 
# KEY index_name(name)<==name字段普通索引

(2)mysql> desc student; 查看刚刚创建的表结构。
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(4)      | NO   | PRI | NULL    | auto_increment |
| name  | char(20)    | NO   | MUL | NULL    |                |
| age   | tinyint(2)  | NO   || 0       |                |
| dept  | varchar(16) | YES  |     | NULL|                |
+-------+-------------+------+-----+---------+----------------+

#PRL为主键的标示,MUL为普通索引的表示 ,auto_increnment 代表数据自增3)利用alter命令修改id列为自增主键值
alter table student change id id int primary key auto_increment; 

创建的表的时候,可以指定
mysql> create table student(
id int(4) not null AUTO_INCREMENT,
name char(20) not null,
age tinyint(2) NOT NULL default '0',
dept varchar(16)  default NULL,
primary key(id),
KEY index_name(name)      
);

提示:
KEY index_name(name)               <==name字段普通索引
优化:在唯一值多的列上建索引查询效率高
还可以自定义自增的长度
EBGUBE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

(4)查看索引【前提都需要进入库】
show index from student; 
查看索引\G 可以查看的更详细:show index from student\G      

(2)查看表结构

(1)语法:desc 表名
(2)示例:desc student; 

(3)建表后利用alter增加普通索引,删除建表时创建的index_name索引

1)语法:alter table 表名 add|drop index 索引名称
alter table student add index index_name;
alter table student drop index index_name;
(2)示例:
create index index_name on student(name);     #创建索引
show index from student;                     #查看索引
create index index_age on student(name(8));   #创建指定n个字符索引
show index from student\G     #查看索引

(4)为表的多个字段创建联合索引

如果查询数据的条件是多列时,我们可以为多个查询的列创建联合索引,甚至,可以为多个列的前n个字符创建联合索引,演示如下:
创建联合索引,和单个索引不冲突

 create index ind_name_dept on student(name,dept);    #在student表创建联合索引
 联合索引作用,查询更快
 show index from student\G
 创建联合索引,并指定值大小:
 create index ind_name_dept on student(name(8),dept(10));
#name 前8个字符,dept 前10个字符
#提示:尽量在唯一值多的大表上建立索引。

什么时候创建联合索引?

只有程序用这两个条件查询,采用联合索引,这个主要是看开发。 
提示:按条件列查询数据时,联合索引是由前缀生效特性的

(5) 创建唯一索引(非主键)

create unique index uni_ind_name on student(name);

(6)索引小结:

创建主键索引:
alter table student chage id id int primary key auto_increment;
删除主键索引(主键列不能自增):
alter table student drop primary key;
添加普通索引:
alter table student add index index_dept(dept);
根据的前n个字符创建索引:
create index index_dept on student(dept(8));
根据多个列创建联合索引:
create index index_name_dept on student(name,dept);
创建唯一索引:
create unique index uni_ind_name on student(name);
删除普通索引与唯一索引:
alter table student drop index index_dept;
drop index index_dept on student;

(7)索引列的创建及生效条件

Q1:既然索引可以加快查询速度,那么就给所有的列加索引吧?
A1:因为索引不但占用系统空间,而且更新数据时还需要维护索引数据的,因此索引是一把双刃剑,并不是越多越好,例如:数十到几百行的小表上无需建立索引,插入更新频繁,读取比较少的需要少建立索引.

Q2:需要在哪些列上创建索引才能加快查询速度呢?
select user,host from mysql.user where
password=…..,索引一定要创建在where后的条件列上,而不是select后的选择数据的列上。另外,我们要尽量选择在唯一值多的大表上的列建立索引,例如,男女生性别列唯一值少,不适合建立索引。

(8)查看唯一值数量

select count(distinct user) from mysql.user;
唯一值就是相同的数量,例如查询user那么相同的user就是唯一值

(9)创建索引的基本知识小结:

■ 索引类似书籍的目录,会加快查询数据的速度 
■ 要在表的列(字段)上创建索引 
■ 索引会加快查询速度,但是也会影响更新的速度,因为更新要在维护索引数据 
■ 索引列并不是越多越好,要在频繁查询的表语句where后的条件列上创建索引 
■ 小表或重复值很多的列上可以不建索引,要在大表以及重复值少的条件上创建索引 
■ 多个列联合索引有前缀生效特性 
■ 当字段内容前N个字符已经接近唯一时,可以对字段的前N个字符创建索引 
■ 索引从工作方式区别,有主键,唯一,普通索引 
■ 索引类型有BTREE(默认)和hash(适合做缓存(内存数据库))等。

(10)主键索引和唯一索引的区别

(1)对于主键/unique constraint oracle/sql server/mysql等都会自动建立唯一索引; 
(2)主键不一定只包含一个字段,所以如果你在主键的其中一个字段建唯一索引还是必要的; 
(3)主健可作外健,唯一索引不可; 
(4)主健不可为空,唯一索引可; 
(5)主健也可是多个字段的组合; 
(6)主键与唯一索引不同的是: 
a.有not null属性; 
b.每个表只能有一个。

5、往表中插入数据

1)命令语法:insert into <表名>[(<字段名1>[..<字段名n>])]values(值1)[,(值n)]
(2)建立测试表:
CREATE TABLE `test1` (
  `id` int(4) NOT NULL,
  `name` char(16) NOT NULL,
  `age` int(2) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
(3)插入值
insert into test1(id,name,age) values(1,'gaoyuliang',60);
insert into test1 values(2,"xiaoqiang",12);
(4)查询
select * from test1;
+----+------------+------+
| id | name       | age  |
+----+------------+------+
|  1 | gaoyuliang |   60 |
|  2 | xiaoqiang  |   12 |
+----+------------+------+
(5)批量插入
insert into test1 values(3,'xiaohong',20),(4,'xiaogang',23);
MariaDB [oldboy]> select * from test1;
+----+------------+------+
| id | name       | age  |
+----+------------+------+
|  1 | gaoyuliang |   60 |
|  2 | xiaoqiang  |   12 |
|  3 | xiaohong   |   20 |
|  4 | xiaogang   |   23 |
+----+------------+------+
(6)清空表中所有值
MariaDB [oldboy]> truncate table test1;
Query OK, 0 rows affected (0.00 sec)

MariaDB [oldboy]> select * from test1;
Empty set (0.00 sec)

(7)一条命令创建
MariaDB [oldboy]> insert into test1 values (1,'oldboy',40),(2,'oldgirl',60),(3,'inca',20),(4,'zuma',30),(5,'kaka',33);
Query OK, 5 rows affected (0.00 sec)
Records: 5  Duplicates: 0  Warnings: 0

MariaDB [oldboy]> select * from test1;
+----+---------+------+
| id | name    | age  |
+----+---------+------+
|  1 | oldboy  |   40 |
|  2 | oldgirl |   60 |
|  3 | inca    |   20 |
|  4 | zuma    |   30 |
|  5 | kaka    |   33 |
+----+---------+------+
5 rows in set (0.00 sec)

6、查询数据

1)语法:select <字段1,字段2,…> from <表名> where <表达式>
#其中,select,from,where是不能随便改的,是关键字,支持大小写2)不进入库查询
MariaDB [(none)]> select * from oldboy.test1 where name="oldboy";
+----+--------+------+
| id | name   | age  |
+----+--------+------+
|  1 | oldboy |   40 |
+----+--------+------+
1 row in set (0.01 sec)
(3)只查询前2行
MariaDB [oldboy]> select * from test1 limit 2;
+----+---------+------+
| id | name    | age  |
+----+---------+------+
|  1 | oldboy  |   40 |
|  2 | oldgirl |   60 |
+----+---------+------+
2 rows in set (0.00 sec)
(4)从第二条开始查,查找2个
MariaDB [oldboy]> select * from test1 limit 1,2;
+----+---------+------+
| id | name    | age  |
+----+---------+------+
|  2 | oldgirl |   60 |
|  3 | inca    |   20 |
+----+---------+------+
2 rows in set (0.00 sec)
(5)按照条件查询
MariaDB [(none)]> select * from oldboy.test1 where name="oldboy";
+----+--------+------+
| id | name   | age  |
+----+--------+------+
|  1 | oldboy |   40 |
+----+--------+------+
#提示:查找字符串类型的条件的值要带单引号,数字值不带引号。6)查询多个条件
MariaDB [oldboy]> select * from test1 where name='oldgirl' and id=2;
+----+---------+------+
| id | name    | age  |
+----+---------+------+
|  2 | oldgirl |   60 |
+----+---------+------+
1 row in set (0.00 sec)
(7)范围查询
MariaDB [oldboy]> select * from test1 where id>2;
+----+------+------+
| id | name | age  |
+----+------+------+
|  3 | inca |   20 |
|  4 | zuma |   30 |
|  5 | kaka |   33 |
+----+------+------+
3 rows in set (0.00 sec)

(8)示例:
创建学生表
drop table student;
create table student(
Sno int(10) NOT NULL COMMENT '学号',
Sname varchar(16) NOT NULL COMMENT '姓名',
Ssex char(2) NOT NULL COMMENT '性别',
Sage tinyint(2)  NOT NULL default '0' COMMENT '学生年龄',
Sdept varchar(16)  default NULL  COMMENT '学生所在系别', 
PRIMARY KEY  (Sno) ,
key index_Sname (Sname)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;

插入内容
create table course(
Cno int(10) NOT NULL COMMENT '课程号',
Cname varchar(64) NOT NULL COMMENT '课程名',
Ccredit tinyint(2) NOT NULL COMMENT '学分',
PRIMARY KEY  (Cno) 
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;

插入内容
CREATE TABLE `SC` (
   SCid int(12) NOT NULL auto_increment COMMENT '主键',
  `Cno` int(10) NOT NULL COMMENT '课程号',
  `Sno` int(10) NOT NULL COMMENT '学号',
  `Grade` tinyint(2) NOT NULL COMMENT '学生成绩',
  PRIMARY KEY  (`SCid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

插入内容
INSERT INTO course values(1001,'Linux中高级运维',3);
INSERT INTO course values(1002,'Linux高级架构师',5);
INSERT INTO course values(1003,'MySQL高级Dba',4);
INSERT INTO course values(1004,'Python运维开发',4);
INSERT INTO course values(1005,'Java web开发',3);

插入内容
INSERT INTO SC(Sno,Cno,Grade)  values(0001,1001,4);
INSERT INTO SC(Sno,Cno,Grade) values(0001,1002,3);
INSERT INTO SC(Sno,Cno,Grade)  values(0001,1003,1);
INSERT INTO SC(Sno,Cno,Grade)  values(0001,1004,6);
INSERT INTO SC(Sno,Cno,Grade)  values(0002,1001,3);
INSERT INTO SC(Sno,Cno,Grade)  values(0002,1002,2);
INSERT INTO SC(Sno,Cno,Grade)  values(0002,1003,2);
INSERT INTO SC(Sno,Cno,Grade)  values(0002,1004,8);
INSERT INTO SC(Sno,Cno,Grade)  values(0003,1001,4);
INSERT INTO SC(Sno,Cno,Grade)  values(0003,1002,4);
INSERT INTO SC(Sno,Cno,Grade)  values(0003,1003,2);
INSERT INTO SC(Sno,Cno,Grade)  values(0003,1004,8);
INSERT INTO SC(Sno,Cno,Grade)  values(0004,1001,1);
INSERT INTO SC(Sno,Cno,Grade)  values(0004,1002,1);
INSERT INTO SC(Sno,Cno,Grade)  values(0004,1003,2);
INSERT INTO SC(Sno,Cno,Grade)  values(0004,1004,3);
INSERT INTO SC(Sno,Cno,Grade)  values(0005,1001,5);
INSERT INTO SC(Sno,Cno,Grade)  values(0005,1002,3);
INSERT INTO SC(Sno,Cno,Grade)  values(0005,1003,2);
INSERT INTO SC(Sno,Cno,Grade)  values(0005,1004,9);

检查,查看表格式或者表内容
MariaDB [oldboy]> desc SC; or select * from SC;
+-------+------------+------+-----+---------+----------------+
| Field | Type       | Null | Key | Default | Extra          |
+-------+------------+------+-----+---------+----------------+
| SCid  | int(12)    | NO   | PRI | NULL    | auto_increment |
| Cno   | int(10)    | NO   |     | NULL    |                |
| Sno   | int(10)    | NO   |     | NULL    |                |
| Grade | tinyint(2) | NO   |     | NULL    |                |
+-------+------------+------+-----+---------+----------------+