Linux高级篇--MYSQL数据库基础知识、数据库安装、SQL语句以及数据库和表管理

Linux高级篇–MYSQL数据库基础知识、数据库安装、SQL语句以及数据库和表管理

一、 关系型数据库基础

数据库的发展史

  • 萌芽阶段:文件系统
      使用磁盘文件来存储数据
  • 初级阶段:第一代数据库
      出现了网状模型、层次模型的数据库
  • 中级阶段:第二代数据库
      关系型数据库和结构化查询语言
  • 高级阶段:新一代数据库
      “关系-对象”型数据库

文件管理系统的缺点

  • 编写应用程序不方便
  • 数据冗余不可避免
  • 应用程序依赖性
  • 不支持对文件的并发访问
  • 数据间联系弱
  • 难以按用户视图表示数据
  • 无安全控制功能

数据库管理系统的优点

  • 相互关联的数据的集合
  • 较少的数据冗余
  • 程序与数据相互独立
  • 保证数据的安全、可靠
  • 最大限度地保证数据的正确性
  • 数据可以并发使用并能同时保证一致性

数据库管理系统及其基本功能和机构

  • 数据库管理系统
    数据库是数据的汇集,它以一定的组织形式存于存储介质上
    DBMS是管理数据库的系统软件,它实现数据库系统的各种功能。是数据库系统的核心
    DBA:负责数据库的规划、设计、协调、维护和管理等工作
    应用程序指以数据库为基础的应用程序
  • 数据库管理系统的基本功能
    数据定义
    数据处理
    数据安全
    数据备份
  • 数据库系统机构
    单机架构
    大型主机/终端架构
    主从式架构(C/S)
    分布式架构

关系型数据库

  • 关系:关系就是二维表。并满足如下性质:
      表中的行、列次序并不重要
  • 行row:表中的每一行,又称为一条记录
  • 列column:表中的每一列,称为属性,字段
  • 主键(Primary key):用于惟一确定一个记录的字段
  • 域domain:属性的取值范围,如,性别只能是‘男’和‘女’两个值

关系数据库

  • RDBMS:关系数据库
      MySQL: MySQL, MariaDB, PerconaServer
      PostgreSQL: 简称为pgsql,EnterpriseDB
      Oracle
      MSSQL
      DB2
  • 数据库排名:
      https://db-engines.com/en/ranking

实体-联系模型E-R

  • 实体Entity
    客观存在并可以相互区分的客观事物或抽象事件称为实体。
    在E-R图中用矩形框表示实体,把实体名写在框内
  • 属性
    实体所具有的特征或性质
  • 联系
    联系是数据之间的关联集合,是客观存在的应用语义链
    实体内部的联系:指组成实体的各属性之间的联系。如职工实体中,职工号和部门经理号之间有一种关联关系
    实体之间的联系:指不同实体之间联系。例学生选课实体和学生基本信息实体之间
    实体之间的联系用菱形框表示

联系类型

  • 联系的类型

一对一联系(1:1)
  如:学员a的基本信息对应其就业信息
一对多联系(1:n)

学员a的信息表对应考试成绩表,成绩表包括月考成绩,期中考试成绩,期末考试成绩,两个表之间通过学员id号关联,学员的一个id号对应多个考试成绩
学员成绩表被学员信息表中的id号所约束,因此学员成绩表依赖于学员信息表

  外键 foreign key 简称FK
  主键 简称PK
  一对多用主外键来实现
  主键表:被外键表依赖的表,即学员信息表
  外键表:依赖于其他的表(主键表),即学员成绩表
  外键字段:外键表依赖于主键表的字段,即id号
  主键表中被外键表依赖的字段必须是主键
多对多联系(m:n)

课程与学员之间的关系就是多对多
学员表   student
课程表   class
使用第三张表student_class实现课程与学员之间的关系
student表
id   name  sex
1     a     f
2     b     m
3     c     f

class  课程表
id  classname
1    linux
2    python
3    java

student_class表
id   student_id   class_id
1       1           1
2       1           2
3       2           2
student_class表中的student_id、class_id属于外键,student表中的学员id号和class表中的课程id号属于相对应的主键
这样就实现了两张表的多对多的关系
对对多对的表操作进行查询,因为涉及到多个表,所以性能会差
  • 数据的操作:
      数据提取:在数据集合中提取感兴趣的内容。SELECT
      数据更新:变更数据库中的数据。INSERT、DELETE、UPDATE
  • 数据的约束条件:是一组完整性规则的集合
      实体(行)完整性Entity integrity
      域(列)完整性Domain Integrity
      参考完整性Referential Integrity

简易数据规划流程

  • 第一阶段:收集数据,得到字段
    收集必要且完整的数据项
    转换成数据表的字段
  • 第二阶段:把字段分类,归入表,建立表的关联
    关联:表和表间的关系
    分割数据表并建立关联的优点
    节省空间
    减少输入错误
    方便数据修改
  • 第三阶段:
    规范化数据库

数据库的正规化分析

  • RDMBS设计范式基础概念
    设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同范式,各种范式呈递次规范,越高的范式数据库冗余越小
  • 目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴德斯科范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。满足最低要求的范式是第一范式(1NF)。在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF),其余范式以次类推。一般说来,数据库只需满足第三范式(3NF)即可

范式

  • 1NF:无重复的列,每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。除去同类型的字段,就是无重复的列
    说明:第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库
    示例:
1NF:
作者   书名1    书名2
a     linux   python
b     python
有属性相同的列:书名
作者   书名1   
a     linux,python
b     python
同一行有多个值
以上两种均不符合第一范式
解决方法:
a     linux  
a     oython
b     python
  • 2NF:属性完全依赖于主键,第二范式必须先满足第一范式,要求表中的每个行必须可以被唯一地区分。通常为表加上一个列,以存储各个实例的唯一标识PK,非PK的字段需要与整个PK有直接相关性
    示例:
员工信息表
name  city  sex  phone  citynumber(城市区号)
a      bj                010
b      sh                021
复合主键:把多个字段(name,city)纳入主键,两个字段其中一个字段可以重复,但是两个一起不能重复
这时,区号citynumber只依赖于city,而不依赖于name,该属性没有完全依赖于主键,这就违反了第二范式
解决方法:
name   city
a       1
b       2
b       2
cityid  city   citynumber
1        bj       010
2        sh       021
  • 3NF:属性不依赖于其它非主属性,满足第三范式必须先满足第二范式。第三范式要求一个数据库表中不包含已在其它表中已包含的非主关键字信息,非PK的字段间不能有从属关系
    示例:
id  name  city  sex  phone  citynumber(城市区号)
1    a      bj                010
2    a      sh                021
3    b      sh                021
这里使用id号作为主键
这时,citynumber城市区号依赖于city,而city不属于主键;其他属性依赖于非主属性,违反了第三范式
解决方法:构建第三张表
id  name   city
1    a       1
2    b       2
3    b       2
cityid  city   citynumber
1        bj       010
2        sh       021

缺点:多表操作,数据库性能会变差

SQL概念

  • SQL: Structure Query Language
      结构化查询语言
      SQL解释器:
      数据存储协议:应用层协议,C/S
  • S:server, 监听于套接字,接收并处理客户端的应用请求
  • C:Client
      客户端程序接口
        CLI
        GUI
      应用编程接口
        ODBC:Open Database Connectivity
        JDBC:Java Data Base Connectivity

约束

  • 约束:constraint,表中的数据要遵守的限制
      主键:一个或多个字段的组合,填入的数据必须能在本表中唯一标识本行;必须提供数据,即NOT NULL,一个表只能有一个
      惟一键:一个或多个字段的组合,填入的数据必须能在本表中唯一标识本行;允许为NULL,一个表可以存在多个
      外键:一个表中的某字段可填入的数据取决于另一个表的主键或唯一键已有的数据
      检查:字段值在一定范围内

基本概念

  • 索引:将表中的一个或多个字段中的数据复制一份另存,并且按特定次序排序存储
  • 关系运算:
      选择:挑选出符合条件的行
      投影:挑选出需要的字段
      连接:表间字段的关联

数据模型

  • 数据抽象:
      物理层:数据存储格式,即RDBMS在磁盘上如何组织文件
      逻辑层:DBA角度,描述存储什么数据,以及数据间存在什么样的关系
      视图层:用户角度,描述DB中的部分数据
  • 关系模型的分类:
      关系模型
      基于对象的关系模型
      半结构化的关系模型:XML数据

二、 MySQL数据库

2.1 MySQL介绍

MySQL历史

  • 1979年:TcX公司Monty Widenius,Unireg
  • 1996年:发布MySQL1.0,Solaris版本,Linux版本
  • 1999年:MySQL AB公司,瑞典
  • 2003年:MySQL 5.0版本,提供视图、存储过程等功能
  • 2008年:Sun 收购
  • 2009年:Oracle收购sun
  • 2009年:Monty成立MariaDB

MySQL和MariaDB

  • 官方网址:
      https://www.mysql.com/
      http://mariadb.org/
  • 官方文档
      https://dev.mysql.com/doc/
      https://mariadb.com/kb/en/
  • 版本演变:
      MySQL:5.1 --> 5.5 --> 5.6 --> 5.7 -->8.0
      MariaDB:5.5 -->10.0–> 10.1 --> 10.2 --> 10.3

MYSQL的特性

  • 插件式存储引擎:也称为“表类型”,存储管理器有多种实现版本,功能和特性可能均略有差别;用户可根据需要灵活选择,Mysql5.5.5开始innoDB引擎是MYSQL默认引擎
      MyISAM==> Aria
      InnoDB==> XtraDB
  • 单进程,多线程
  • 诸多扩展和新特性
  • 提供了较多测试组件
  • 开源
2.2 安装MySQL
  • Mariadb安装方式:
    1、源代码:编译安装
    2、二进制格式的程序包:展开至特定路径,并经过简单配置后即可使用
    3、程序包管理器管理的程序包
      CentOS安装光盘
      项目官方:https://downloads.mariadb.org/mariadb/repositories/
如果不想使用光盘自带的数据库,而是使用相对较新的数据库,可以使用官方提供的yum源进行安装
[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.2/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
注意:在配置yum源时,要配置本地yum源,以解决依赖关系;安装新版本数据库名称为MariaDB-server

RPM包安装MySQL

  • RPM包安装
      CentOS7:安装光盘直接提供
        mariadb-server 服务器包
        mariadb客户端工具包
      CentOS6
  • 使用yum安装,存在以下问题:
    (1)存在匿名用户以及空口令,即任何用户都可以以空口令登录
    (2)所有登录用户只能在本地登录,不能远程登录
    (3)默认存在test测试数据库,该数据库供新手练习使用,可以删除
  • 使用以下脚本,提高数据库安全性
    mysql_secure_installation
      设置数据库管理员root口令
      禁止root远程登录
      删除anonymous用户帐号
      删除test数据库
    脚本运行过程如下:
[root@centos7-1 ~]#mysql_secure_installation 

NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
      SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MariaDB to secure it, we'll need the current
password for the root user.  If you've just installed MariaDB, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none):       写入当前mysql数据库root口令,默认没有口令,直接敲enter键
OK, successfully used password, moving on...

Setting the root password ensures that nobody can log into the MariaDB
root user without the proper authorisation.

Set root password? [Y/n] y                       是否设置root口令
New password:                                    写入新口令
Re-enter new password:                           再次确认口令
Password updated successfully!
Reloading privilege tables..
 ... Success!


By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] y              是否移除匿名用户
 ... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] y       是否禁止root远程登录
 ... Success!

By default, MariaDB comes with a database named 'test' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] y   是否移除test测试数据库
 - Dropping test database...
 ... Success!
 - Removing privileges on test database...
 ... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] y      是否立即下载权限表
 ... Success!

Cleaning up...

All done!  If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!

注意:如果设置有误,可以再次运行脚本进行设置
一旦改脚本运行过以后,想再次以匿名用户或者空口令登录,将不会被允许

MariaDB程序

  • 客户端程序:
      mysql: 交互式的CLI工具
      mysqldump:备份工具,基于mysql协议向mysqld发起查询请求,并将查得的所有数据转换成insert等写操作语句保存文本文件中
      mysqladmin:基于mysql协议管理mysqld
      mysqlimport:数据导入工具
  • MyISAM存储引擎的管理工具:
      myisamchk:检查MyISAM库
      myisampack:打包MyISAM表,只读
  • 服务器端程序
      mysqld_safe
      mysqld
      mysqld_multi:多实例,示例:mysqld_multi–example
       mysql默认不支持多实例,要想实现多实例,准备多个mysql安装程序,把配置文件加以修改,使得各自的端口号均不一样,每个实例之间相互独立,互不影响

用户账号

  • mysql用户账号由两部分组成:
      ‘USERNAME’@‘HOST’
  • 说明:
      HOST限制此用户可通过哪些远程主机连接mysql服务器
      支持使用通配符:
        % 匹配任意长度的任意字符
          172.16.0.0/255.255.0.0 或172.16.%.%
        _ 匹配任意单个字符

MySQL客户端

  • mysql使用模式:
  • 交互式模式:
      可运行命令有两类:
        客户端命令:
          \h, help
          \u,use
          \s,status
          \!,system
        服务器端命令:
          SQL, 需要语句结束符;
  • 脚本模式:
      mysql –u USERNAME -p PASSWORD < /path/somefile.sql
      mysql> source /path/from/somefile.sql
[root@centos7-1 ~]#cat test.sql 
show databases;
[root@centos7-1 ~]#mysql -uroot -pcentos123456 < test.sql 
Database
information_schema
mysql
performance_schema
注意:该命令显示结果中的列表与在mysql数据库中执行命令有细微差别,即不带边框 
  • mysql客户端可用选项:
      -A, --no-auto-rehash 禁止补全
      -u, --user=用户名,默认为root
      -h, --host=服务器主机,默认为localhost
      -p, --passowrd=用户密码,建议使用-p,默认为空密码
      -P, --port=服务器端口
      -S, --socket=指定连接socket文件路径
      -D, --database= 指定默认数据库
      -C, --compress启用压缩
      -e “SQL“执行SQL命令
      -V, --version显示版本
      -v --verbose显示详细信息
      --print-defaults 获取程序默认使用的配置

socket地址

  • 服务器监听的两种socket地址:
      ipsocket: 监听在tcp的3306端口,支持远程通信
      unixsock: 监听在sock文件上,仅支持本机通信
        如:/var/lib/mysql/mysql.sock
      说明:host为localhost,127.0.0.1时自动使用unixsock
如果客户端服务器在同一台主机,即使服务端口号没有打开也能连接
[root@centos7-1 ~]#iptables -A INPUT -p tcp --dport 3306 -j REJECT
[root@centos7-1 ~]#mysql -uroot -p 
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 31
Server version: 5.5.56-MariaDB MariaDB Server

Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> 

注意:此时mysql -uroot -p 相当于mysql -uroot -p -hlocalhost,即在本机登录。
当客户端和服务器端在同一台主机,客户端登录服务器端并不是通过网络,也没有通过端口号,而是通过/usr/lib/mysql/mysql.socket文件进行连接,socket相当于文件传输中转站,只在本地生效,如果客户端跨网络访问服务端时,则socket文件不生效
如果删除该文件,则客户端无法在本机连接服务端
mysql.socket文件,在服务启动时创建,服务关闭时将不存在;
因此只需重启服务,该文件即可重新生成

执行命令

  • 运行mysql命令:默认空密码登录
      mysql>use mysql
      mysql>select user();查看当前用户
      mysql>SELECT User,Host,PasswordFROM user;
  • 登录系统:mysql –uroot –p
  • 客户端命令:本地执行
      mysql> help
      每个命令都完整形式和简写格式
      mysql> status 或\s
  • 服务端命令:通过mysql协议发往服务器执行并取回结果
      每个命令都必须命令结束符号;默认为分号
      SELECT VERSION();

知识扩展:更改数据库终端提示符
查看mysqlman帮助: man mysql
搜索prompt,查看提示符修改表格

格式: 
在linux中执行:
shell> mysql --prompt="(\u@\h) [\d]> "  这种更改只是临时的,下次登录如果不写就会恢复默认
想要永久保存,需要把更改写入配置文件中
vim  /etc/profile.d/env.sh    把变量写入配置文件中
export MYSQL_PS1="(\u@\h) [\d]> "   声明变量
source  /etc/profile.d/env.sh   使文件立即生效

或者写入数据库客户端配置文件语句块中
vim /etc/my.cnf.d/mysql-clients.cnf
[mysql]
prompt="\\r:\\m:\\s> " 

注意:这两个文件生效的优先级:/etc/my.cnf.d/mysql-clients.cnf文件优先级大于/etc/profile.d/env.sh文件,即数据库客户端配置文件优先生效
另外,在工作中要把生产环境与测试环境的提示符区分开,防止混淆

服务器端配置

  • 服务器端(mysqld):工作特性有多种配置方式
  • 1、命令行选项:
  • 2、配置文件:类ini格式
    集中式的配置,能够为mysql的各应用程序提供配置信息
      [mysqld] 服务器端配置语句块
      [mysqld_safe] 服务端安全性配置语句块
      [mysqld_multi] 服务端多实例配置语句块
      [mysql] 客户端配置语句块
      [mysqldump] 客户端数据库备份语句块
      [server] 服务器配置语句块
      [client] 客户端配置语句块
    格式:parameter = value
    说明:_和-相同
      1,ON,TRUE意义相同,0,OFF,FALSE意义相同

配置文件

  • 配置文件:
    文件优先级从上到下,优先级逐渐变高,文件如下:
/etc/my.cnf            Global选项  
/etc/mysql/my.cnf      Global选项  
SYSCONFDIR/my.cnf      Global选项  
$MYSQL_HOME/my.cnf     Server-specific 选项  
--defaults-extra-file=path  
~/.my.cnf              User-specific 选项  

一般情况下,写入/etc/my.cnf配置文件中

MariaDB配置

  • 侦听3306/tcp端口可以在绑定有一个或全部接口IP上
  • vim /etc/my.cnf
    [mysqld]
    skip-networking=1
    关闭网络连接,只侦听本地客户端,所有和服务器的交互都通过一个socket实现,socket的配置存放在/var/lib/mysql/mysql.sock)可在/etc/my.cnf修改

通过二进制格式安装过程

  • 二进制格式安装过程(以mariadb-10.2.18版本为例)
    (1)准备数据目录
    创建逻辑卷,供mysql存放数据使用,因为mysql存放的数据会逐渐增加,使用逻辑卷便于扩展。对硬盘进行分区,创建10G大小的分区(10G为做实验时划分的大小,在实际生产环境中,根据需求进行划分),要注意更改分区标签为8e(lvm类型),分区完毕后同步分区
    创建分区为/dev/sda6
    创建逻辑卷:
pvcreate /dev/sda6  
vgcreate vg_data /dev/sda6  
lvcreate -n lv_mysql -l 100%FREE vg_data  
mkfs.xfs  /dev/vg_data/lv_mysql

vim /etc/fstab  
UUID=ba3abbaf-b064-40b8-9127-f4f9453133f2   /mysql   xfs    defaults   0  0     把逻辑卷挂在到/mysql目录下,该目录用于存放数据库数据

mount -a
(2) 创建mysql用户和mysql组

mkdir /mysql/data        手动创建用户家目录  
chown mysql.mysql /mysql/data   更改家目录所有者和所属组  
useradd -r -s /sbin/nologin  -d /mysql/data  mysql  

注意:在创建用户时,不能指定用户家目录(即-m选项,创建用户家目录),否则数据库安装完毕后,会自动创建以家目录中文件名为命名的数据库
(3) 准备二进制程序
tar xvf mariadb-10.2.18-linux-x86_64.tar.gz -C /usr/local/
注意:这里解压缩的文件路径必须指定为/usr/local目录,因为该文件在编译时就以该目录作为数据库应用程序存放位置。
另外,由于解压后的文件带有版本号,而该文件默认不能有版本号信息,因此,创建软链接指向该文件,而且这样的做法利用灰度发布的思路,有利于版本的切换(只需更改软链接即可)

cd /usr/local/
ln -s mariadb-10.2.18-linux-x86_64/  mysql/

此时,/usr/local/mariadb-10.2.18-linux-x86_64目录下文件所有者和所属组有问题,因此需要更改该目录下所有文件的所有者和所属组
chown -R root:mysql /usr/local/mysql/
(4) 准备配置文件
配置文件可根据系统提供的模板进行修改
配置文件模板所在路径:/usr/local/mysql/support-files/
该目录下有四个模板文件,每个数据库配置文件支持的内存大小不同
my-small.cnf 支持小于等于64M内存
my-medium.cnf 支持32M-64M内存
my-large.cnf 支持512M内存
my-huge.cnf 支持1G-2G内存
根据需求,选择不同的模板文件,在这里我们使用my-huge.cnf模板文件
另外,为了防止与系统自带的数据库配置文件冲突,把配置文件存放到/etc/mysql目录下并命名为my.cnf,因为该目录下配置文件优先级高于系统自带配置文件/etc/my.cnf,该目录需要手动创建

mkdir  /etc/mysql/   
cd  /usr/local/mysql/support-files
cp  my-huge.cnf  /etc/mysql/my.cnf
更改配置文件:
vim  /etc/mysql/my.cnf
[mysqld]
datadir=/mysql/data      指定数据存放路径
innodb_file_per_table=on
skip_name_resolve=on 

innodb_file_per_table= on   数据库的每一个表都生成一个独立的文件,便于管理;默认情况下,所有的表存放在一个文件中,这样不利于管理。该文件在10.2以上版本的数据库默认开启此功能,可以不用添加
skip_name_resolve= on   禁止把ip反向解析为名字,因为反向解析会降低数据库的性能,因此建议关闭反向解析

(5)创建数据库文件

cd/usr/local/mysql/  
./scripts/mysql_install_db--datadir=/app/data --user=mysql    

(6)准备服务脚本,并启动服务
服务脚本可以参考系统中提供的模板文件:/usr/local/mysql/support-files/mysql.server

cp  /usr/local/mysql/support-files/mysql.server   /etc/init.d/mysqld  
把服务脚本复制到系统服务目录下重命名为mysqld,系统启动即可启动该服务
chkconfig --add mysqld  把服务加入服务列表中
service mysqld  start  启动服务,由于该服务是二进制编译安装,因此启动服务使用service命令
为了便于使用,把该命令所在路径加入PATH变量
echo PATH=/usr/local/mysqld/bin:$PATH > /etc/profile.d/mysqld.sh 

(7)安全初始化
/user/local/mysql/bin/mysql_secure_installation
至此,二进制安装mysql完成

源码编译安装mariadb

  • 安装编译依赖的软件包
yum -y install bison bison-develzlib-devel libcurl-devel libarchive-devel boost-develgccgcc-c++ cmakencurses-devel gnutls-devel libxml2-devel openssl-devel libevent-devel libaio-devel   
  • 做准备用户和数据目录
mkdir/data  
useradd -r -s /sbin/nologin -d /data/mysql mysql
tar xvfmariadb-10.2.15.tar.gz  
  • cmake编译安装:
    cmake的重要特性之一是其独立于源码(out-of-source)的编译功能,即编译工作可以在另一个指定的目录中而非源码目录中进行,这可以保证源码目录不受任何一次编译的影响,因此在同一个源码树上可以进行多次不同的编译,如针对于不同平台编译
    编译选项:https://dev.mysql.com/doc/refman/5.7/en/source-configuration-options.html
cd mariadb-10.2.15/   
cmake . -DCMAKE_INSTALL_PREFIX=/app/mysql -DMYSQL_DATADIR=/data/mysql/  -DSYSCONFDIR=/etc -DMYSQL_USER=mysql -DWITH_INNOBASE_STORAGE_ENGINE=1  -DWITH_ARCHIVE_STORAGE_ENGINE=1 -DWITH_BLACKHOLE_STORAGE_ENGINE=1 -DWITH_PARTITION_STORAGE_ENGINE=1  -DWITHOUT_MROONGA_STORAGE_ENGINE=1 -DWITH_DEBUG=0 -DWITH_READLINE=1 -DWITH_SSL=system -DWITH_ZLIB=system -DWITH_LIBWRAP=0 -DENABLED_LOCAL_INFILE=1 -DMYSQL_UNIX_ADDR=/data/mysql/mysql.sock  -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci  
提示:如果出错,执行rm-f CMakeCache.txt
  • 生成数据库文件
cd/app/mysql/  
scripts/mysql_install_db--datadir=/data/mysqldb/ --user=mysql
  • 准备配置文件
    cp /app/mysql/support-files/my-huge.cnf/etc/my.cnf
  • 准备启动脚本
    cp /app/mysql/support-files/mysql.server/etc/init.d/mysqld
  • 准备环境变量
echo 'PATH=/app/mysql/bin:$PATH' > /etc/profile.d/mysql.sh  
. /etc/profile.d/mysql.sh
  • 启动服务
    chkconfig--add mysqld;service mysqldstart

实验:实现数据库多实例

  • 实现数据库多实例
    主要在测试环境中使用,多实例可以使相同版本,也可是使用不同版本

  • 实现多实例需要提前准备:
    1、用户
    2、数据库存放数据的目录
    3、数据库配置文件
    4、数据库的启动脚本
    5、数据库中存放系统数据的数据库文件

  • 如果基于同一版本mysql数据库实现多实例:
    1、二进制安装程序可使用同一个
    2、应用程序可以使用同一个
    3、用户账号可以是同一个
    4、存放数据库的目录是各自独立的
    5、配置文件是独立的,每个数据库的端口可能也不一样
    6、服务的启动脚本是独立的,里面监听的端口号也不一样

  • yum安装mariadb实现多实例

mysql账号自动生成
[root@centos7 ~]# getent passwd mysql
mysql:x:27:27:MariaDB Server:/var/lib/mysql:/sbin/nologin
二进制程序默认目录:/usr/libexec/mysqld

规划:
自定义端口号:3306  3307  3308
存放数据库的目录:
/data/mysql/{3306,3307,3308}
以3306为例:
/data/mysql/3306/{etc,log,data,pid,bin}
etc   存放配置文件
log   存放日志文件
data  存放数据库的数据
pid   存放数据库的进程
bin   存放数据库的二进制程序

(1)创建所需的各个目录
mkdir -pv /data/mysql/{3306,3307,3308}/{etc,data,socket,log,bin,pid}
[root@centos7 data]# tree mysql
mysql
├── 3306
│   ├── bin
│   ├── data
│   ├── etc
│   ├── log
│   ├── pid
│   └── socket
├── 3307
│   ├── bin
│   ├── data
│   ├── etc
│   ├── log
│   ├── pid
│   └── socket
└── 3308
    ├── bin
    ├── data
    ├── etc
    ├── log
    ├── pid
    └── socket
更改mysql目录的所有者和所属组为mysql
chown -R mysql.mysql  mysql

(2)准备数据库数据文件:
生成系统数据库文件,使用系统提供的脚本文件:/usr/bin/mysql_install_db
/usr/bin/mysql_install_db --datadir=/data/mysql/3306/data --user=mysql    生成3306端口号的数据库文件,指定存放数据的路径以及用户账号
/usr/bin/mysql_install_db --datadir=/data/mysql/3307/data --user=mysql    生成3307端口号的数据库文件,指定存放数据的路径以及用户账号
/usr/bin/mysql_install_db --datadir=/data/mysql/3308/data --user=mysql     生成3308端口号的数据库文件,指定存放数据的路径以及用户账号

(3)准备配置文件
参考系统生成的数据库配置文件,配置所需的数据库文件
3306端口号数据库配置文件
cp /etc/my.cnf  /data/mysql/3306/etc/
vim /data/mysql/3306/etc/my.cnf 
[mysqld]
port=3306     指定端口号
datadir=/data/mysql/3306/data   指定存放数据的文件路径
socket=/data/mysql/3306/socket/mysql.sock   指定存放socket文件路径

[mysqld_safe]
log-error=/data/mysql/3306/log/mariadb.log  指定存放日志文件路径
pid-file=/data/mysql/3306/pid/mariadb.pid  指定存放pid文件路径

# !includedir /etc/my.cnf.d   自定义数据量不存在子配置文件,注释掉该行

3307端口号数据库配置文件
cp /etc/my.cnf  /data/mysql/3307/etc/
vim /data/mysql/3307/etc/my.cnf 
[mysqld]
port=3307     指定端口号
datadir=/data/mysql/3307/data   指定存放数据的文件路径
socket=/data/mysql/3307/socket/mysql.sock   指定存放socket文件路径

[mysqld_safe]
log-error=/data/mysql/3307/log/mariadb.log  指定存放日志文件路径
pid-file=/data/mysql/3307/pid/mariadb.pid  指定存放pid文件路径

# !includedir /etc/my.cnf.d   自定义数据量不存在子配置文件,注释掉该行

3308端口号数据库配置文件
cp /etc/my.cnf  /data/mysql/3308/etc/
vim /data/mysql/3308/etc/my.cnf 
[mysqld]
port=3308     指定端口号
datadir=/data/mysql/3308/data  指定存放数据的文件路径
socket=/data/mysql/3308/socket/mysql.sock   指定存放socket文件路径

[mysqld_safe]
log-error=/data/mysql/3308/log/mariadb.log  指定存放日志文件路径
pid-file=/data/mysql/3308/pid/mariadb.pid  指定存放pid文件路径

# !includedir /etc/my.cnf.d   自定义数据量不存在子配置文件,注释掉该行

(4)准备mysql服务脚本
可以使用以下脚本实现服务脚本:
vim  mysqld
#!/bin/bash

port=3306       自定义端口号,根据需求进行更改
mysql_user="root"    指定以roo身份启动mysql
mysql_pwd=""         指定mysql的root口令
cmd_path="/usr/bin"    指定mysql程序路径,该路径为yum安装默认路径,如果是二进制安装或者源码编译安装数据库,则根据需求进行更改
mysql_basedir="/data/mysql"   mysql数据库的根目录,根据需求进行更改
mysql_sock="${mysql_basedir}/${port}/socket/mysql.sock"   调用定义变量,指定数据库socket文件路径

function_start_mysql()     定义函数,启动mysql 
{
    if [ ! -e "$mysql_sock" ];then
      printf "Starting MySQL...\n"
      ${cmd_path}/mysqld_safe --defaults-file=${mysql_basedir}/${port}/etc/my.cnf  &> /dev/null  &  使用mysqld_safe命令调用配置文件启动mysql服务
    else
      printf "MySQL is running...\n"
      exit
    fi
}


function_stop_mysql()     定义函数,关闭mysql
{
    if [ ! -e "$mysql_sock" ];then
       printf "MySQL is stopped...\n"
       exit
    else
       printf "Stoping MySQL...\n"
       ${cmd_path}/mysqladmin -u ${mysql_user} -p${mysql_pwd} -S ${mysql_sock} shutdown    使用mysqldadmin命令关闭mysql服务
   fi
}


function_restart_mysql()    定义函数,重启mysql
{
    printf "Restarting MySQL...\n"
    function_stop_mysql
    sleep 2
    function_start_mysql
}

case $1 in     使用case语句进行条件判断调用哪个函数
start)
    function_start_mysql
;;
stop)
    function_stop_mysql
;;
restart)
    function_restart_mysql
;;
*)
    printf "Usage: ${mysql_basedir}/${port}/bin/mysqld {start|stop|restart}\n"
esac

把该脚本复制到各个数据库存放服务脚本的目录下,并把脚本中对应的端口号以及根目录路径进行更改
cp mysqld /data/mysql/3306/bin/  
vim  /data/mysql/3306/bin/mysqld
port=3306
mysql_basedir="/data/mysql"

cp  /data/mysql/3306/bin/mysqld  /data/mysql/3307/bin/mysqld
vim  /data/mysql/3307/bin/mysqld
port=3307

cp  /data/mysql/3306/bin/mysqld  /data/mysql/3308/bin/mysqld
vim  /data/mysql/3308/bin/mysqld
port=3308

服务开机自启动:
3306,3307,3308三个数据库都需要进行设置,这里以3306数据库为例:
cp  /data/mysql/3306/bin/mysqld   /etc/init.d/mysqld3306
vim  /etc/init.d/mysqld3306
#!/bin/bash
#chkconfig: 345 20 80    添加服务启动和关闭级别
#description: mysql 3307   添加描述
chkconfig --add mysqld3306   把服务加入服务启动列表
注意:每个数据库的服务启动和关闭级别不能一样

或者把服务启动脚本存放到/etc/rc.local目录中
vim  /etc/rc.local
/data/mysql/3306/bin/mysqld
/data/mysql/3307/bin/mysqld
/data/mysql/3308/bin/mysqld

对启动脚本增加执行权限
chmod +x  /data/mysql/3306/bin/mysqld
chmod +x  /data/mysql/3307/bin/mysqld
chmod +x  /data/mysql/3308/bin/mysqld


至此,数据库各实例的用户、数据库文件、配置文件、服务启动脚本都已经准备完成

启动服务:
/data/mysql/3306/bin/mysqld start
/data/mysql/3307/bin/mysqld start
/data/mysql/3308/bin/mysqld start

连接数据库:
由于客户端和服务端在同一台主机上,因此可以通过本地socket文件连接数据库
mysql -S /data/mysql/3306/socket/mysql.sock     连接3306数据库
MariaDB [(none)]> show variables like "port";  查看连接端口号
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| port          | 3306  |
+---------------+-------+
1 row in set (0.01 sec)

[root@centos7 ~]# mysql -S /data/mysql/3306/socket/mysql.sock -e 'show variables like "port" '  通过shell命令查看数据库端口号
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| port          | 3306  |
+---------------+-------+

此时,数据库虽然创建完毕,但是数据库登录时却不需要口令,因此还需要对数据库设置登录口令
mysqladmin -uroot -S /data/mysql/3306/socket/mysql.sock  password "centos123456"

通过端口号连接数据库
mysql -uroot -p -P 3306 -h127.0.0.1
[root@centos7 ~]# mysql -uroot -p -P 3306 -h127.0.0.1
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 1
Server version: 5.5.56-MariaDB MariaDB Server

Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> 


注意:在停止服务时,提示需要输入口令
[root@centos7 ~]# /data/mysql/3306/bin/mysqld stop
Stoping MySQL...
Enter password: 
这是因为服务脚本中定义的提示服务函数中存在-p${mysql_pwd}选项
function_stop_mysql()
{
    if [ ! -e "$mysql_sock" ];then
       printf "MySQL is stopped...\n"
       exit
    else
       printf "Stoping MySQL...\n"
       ${cmd_path}/mysqladmin -u ${mysql_user} -p${mysql_pwd} -S ${mysql_sock} shutdown
   fi
}
但此时,启动服务脚本中设置的却是空口令
mysql_pwd=""
解决方法:
方法1:删除服务脚本定义函数中${cmd_path}/mysqladmin -u ${mysql_user} -p${mysql_pwd} -S ${mysql_sock} shutdown即可

方法2:先给3306端口号数据库添加口令,使用mysqlamdin命令添加口令
mysqladmin -uroot -S /data/mysql/3306/socket/mysql.sock  password "centos123456"
然后再启动服务脚本中设置口令项添加设置的口令
mysql_pwd="centos123456"

同样的,3307和3308端口的数据库需要做同样的更改
3307端口号数据库:
设置口令
mysqladmin -uroot -S /data/mysql/3307/socket/mysql.sock  password "centos123456"
更改服务脚本设置密码项
mysql_pwd="centos123456"

3308端口号数据库:
设置口令
mysqladmin -uroot -S /data/mysql/3308/socket/mysql.sock  password "centos123456"
更改服务脚本设置密码项
mysql_pwd="centos123456"
注意:由于密码在服务脚本中以明文方式显示,因此脚本要做好保密措施。或者服务脚本中不写密码,在关闭服务时会出现输入密码提示,再输入密码即可

注意:mysqld_multi该命令也可以实现多实例,但要求必须是同一个数据库版本

三、 管理数据库和表

关系型数据库的常见组件

  • 数据库:database
  • 表:table
      行:row
      列:column
  • 索引:index
  • 视图:view
  • 用户:user
  • 权限:privilege
  • 存储过程:procedure,无返回值
  • 存储函数:function,有返回值
  • 触发器:trigger
  • 事件调度器:event scheduler,任务计划

SQL语言的兴起于语法标准

  • 20世纪70年代,IBM开发出SQL,用于DB2
  • 1981年,IBM推出SQL/DS数据库
  • 业内标准微软和Sybase的T-SQL,Oracle的PL/SQL
  • SQL作为关系型数据库所使用的标准语言,最初是基于IBM的实现在1986年被批准的。1987年,“国际标准化组织(ISO)”把ANSI(美国国家标准化组织) SQL作为国际标准。
  • SQL:ANSI SQL
    SQL-1986, SQL-1989, SQL-1992, SQL-1999, SQL-2003 , SQL-2008,SQL-2011

SQL语言规范

  • 在数据库系统中,SQL语句不区分大小写(建议用大写)
  • SQL语句可单行或多行书写,以“;”结尾
  • 关键词不能跨多行或简写
  • 用空格和缩进来提高语句的可读性
  • 子句通常位于独立行,便于编辑,提高可读性
  • 注释:
      SQL标准:
        /*注释内容*/ 多行注释
        --注释内容单行注释,注意有空格
      MySQL注释:
        #

数据库对象

  • 数据库的组件(对象):
      数据库、表、索引、视图、用户、存储过程、函数、触发器、事件调度器等
  • 命名规则:
      必须以字母开头
      可包括数字和三个特殊字符(# _ $)
      不要使用MySQL的保留字
      同一database(Schema)下的对象不能同名

SQL语句分类

  • SQL语句分类:
    DDL: Data DefinationLanguage 数据定义语言
      CREATE,DROP,ALTER
    DML: Data Manipulation Language数据操纵语言
      INSERT,DELETE,UPDATE
    DCL:Data Control Language 数据控制语言
      GRANT,REVOKE,COMMIT,ROLLBACK
    DQL:Data Query Language 数据查询语言
      SELECT

SQL语句构成

  • SQL语句构成:
    Keyword组成clause
    多条clause组成语句

示例:

SELECT *           SELECT子句
FROM products      FROM子句
WHERE price>400    WHERE子句

说明:一组SQL语句,由三个子句构成,SELECT,FROM和WHERE是关键字

数据库操作

  • 创建数据库:
      CREATE DATABASE|SCHEMA [IF NOT EXISTS] ‘DB_NAME’;
      CHARACTER SET ‘character set name’ 定义子句的字符集
      COLLATE ‘collate name’ 定义子句的排序规则
字符集:推荐选择utf8编码,支持全世界的语言;utf8mb64编码,兼容性更高,支持表情包

示例:

create database db1;  创建数据库
show  create  database  db1;   查看创建数据库命令
注意,数据库默认使用的编码为latin1,即拉丁语
create database db2  character set=utf8mb4;  创建数据库db2,并指定数据库使用的编码格式
show  collation   查看排序规则,排序规则推荐使用默认即可
  • 删除数据库
      DROP DATABASE|SCHEMA [IF EXISTS] ‘DB_NAME’;
  • 查看支持所有字符集:SHOW CHARACTER SET;
  • 查看支持所有排序规则:SHOW COLLATION;
  • 获取命令使用帮助:
      mysql> HELP KEYWORD;
  • 查看数据库列表:
      mysql> SHOW DATABASES;

  • 表:二维关系
  • 设计表:遵循规范
  • 定义:字段,索引
      字段:字段名,字段数据类型,修饰符
      约束,索引:应该创建在经常用作查询条件的字段上

创建表

  • 创建表:CREATE TABLE
    (1) 直接创建
直接创建表(可以分开多行书写):
MariaDB [db1]> create table students (
    -> id int unsigned AUTO_INCREMENT  primary key, 
    -> name varchar (50) NOT NULL,
    -> sex enum('m','f'),     性别定义使用枚举(在男和女之间选其中一个)
    -> age tinyint unsigned default 20
    -> );
show create table students;  查看表的创建
desc students   查看表结构的定义

(2) 通过查询现存表创建;新表会被直接插入查询而来的数据
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name[(create_definition,…)] [table_options] [partition_options]select_statement

select * from  表名;    查看数据库中的某张表
create table newstudents seletc * from students;  查询students表,把表结构和信息导入newstudents表中
MariaDB [hellodb]> select * from newstudents;   此命令查看新表newstudents的内容
MariaDB [hellodb]> desc newstudents;   查看新表的表结构
+-----------+---------------------+------+-----+---------+-------+
| Field     | Type                | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+-------+
| StuID     | int(10) unsigned    | NO   |     | 0       |       |
| Name      | varchar(50)         | NO   |     | NULL    |       |
| Age       | tinyint(3) unsigned | NO   |     | NULL    |       |
| Gender    | enum('F','M')       | NO   |     | NULL    |       |
| ClassID   | tinyint(3) unsigned | YES  |     | NULL    |       |
| TeacherID | int(10) unsigned    | YES  |     | NULL    |       |
+-----------+---------------------+------+-----+---------+-------+
6 rows in set (0.01 sec)

MariaDB [hellodb]> desc students;   查看旧表的表结构
+-----------+---------------------+------+-----+---------+----------------+
| Field     | Type                | Null | Key | Default | Extra          |
+-----------+---------------------+------+-----+---------+----------------+
| StuID     | int(10) unsigned    | NO   | PRI | NULL    | auto_increment |
| Name      | varchar(50)         | NO   |     | NULL    |                |
| Age       | tinyint(3) unsigned | NO   |     | NULL    |                |
| Gender    | enum('F','M')       | NO   |     | NULL    |                |
| ClassID   | tinyint(3) unsigned | YES  |     | NULL    |                |
| TeacherID | int(10) unsigned    | YES  |     | NULL    |                |
+-----------+---------------------+------+-----+---------+----------------+
6 rows in set (0.01 sec)

跨数据库创建表

在db1数据库中创建newstudents表,从hellodb数据库复制students表的结构和内容
MariaDB [db1]> create table newstudents select * from hellodb.students;
Query OK, 25 rows affected (0.01 sec)
Records: 25  Duplicates: 0  Warnings: 0
查询表
MariaDB [db1]> show tables;
+---------------+
| Tables_in_db1 |
+---------------+
| newstudents   |
| students      |
+---------------+
2 rows in set (0.00 sec)
查询表内容
MariaDB [db1]> select * from newstudents;

(3) 通过复制现存的表的表结构创建,但不复制数据
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name{ LIKE old_tbl_name| (LIKE old_tbl_name) }

MariaDB [db1]> create table test like newstudents;   创建新表test,该表为空表 
查看两张表的表结构,发现表结构一致
MariaDB [db1]> desc test;
+-----------+---------------------+------+-----+---------+-------+
| Field     | Type                | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+-------+
| StuID     | int(10) unsigned    | NO   |     | 0       |       |
| Name      | varchar(50)         | NO   |     | NULL    |       |
| Age       | tinyint(3) unsigned | NO   |     | NULL    |       |
| Gender    | enum('F','M')       | NO   |     | NULL    |       |
| ClassID   | tinyint(3) unsigned | YES  |     | NULL    |       |
| TeacherID | int(10) unsigned    | YES  |     | NULL    |       |
+-----------+---------------------+------+-----+---------+-------+
6 rows in set (0.00 sec)

MariaDB [db1]> desc newstudents;
+-----------+---------------------+------+-----+---------+-------+
| Field     | Type                | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+-------+
| StuID     | int(10) unsigned    | NO   |     | 0       |       |
| Name      | varchar(50)         | NO   |     | NULL    |       |
| Age       | tinyint(3) unsigned | NO   |     | NULL    |       |
| Gender    | enum('F','M')       | NO   |     | NULL    |       |
| ClassID   | tinyint(3) unsigned | YES  |     | NULL    |       |
| TeacherID | int(10) unsigned    | YES  |     | NULL    |       |
+-----------+---------------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
查看test表的内容,发现新表test为空
MariaDB [db1]> select * from test;
Empty set (0.00 sec)

知识扩展:

使用以下语法也可以只复制表结构,不复制表内容
create table test2  newstudents select * from hellodb.students where 1=0;
在第二种语法的基础之上,添加一条不成立的判断语句where 1=0即可

另外,数据库在5.5版本中,数据库存在一个缺点:数据库文件所在目录中,数据被集中存放在一个表ibdata1中,并没有存放各自的目录下如(db1,db2,hellodb等),各自目录下只是存放了表的定义,管理起来非常不方便。而10以上版本mariadb数据库则没有这种缺点.
解决方法:
在配置文件/etc/my.cnf中添加innodb_file_per_table=on即可
在之前编译安装数据库准备配置文件时,我们提到过该项

vim  /etc/my.cnf
innodb_file_per_table=on   是指存放表时,每张表分开存放

更改后重启数据库
systemctl restart mariadb
如果再添加新的数据库,每张表将会分开存放

  • 注意:
      Storage Engine是指表类型,也即在表创建时指明其使用的存储引擎,同一库中不同表可以使用不同的存储引擎
      同一个库中表建议要使用同一种存储引擎类型
    CREATE TABLE [IF NOT EXISTS] ‘tbl_name’ (col1 type1 修饰符, col2 type2 修饰符, …)
  • 字段信息
      col type1 字段类型
      PRIMARY KEY(col1,…) 主键
      INDEX(col1, …) 索引
      UNIQUE KEY(col1, …) 惟一键
  • 表选项:
      ENGINE [=] engine_name 存储引擎名称
        SHOW ENGINES;查看支持的engine类型
      ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT}
  • 获取帮助:mysql> HELP CREATE TABLE;

表操作

  • 查看所有的引擎:SHOW ENGINES
  • 查看表:SHOW TABLES [FROM db_name]
  • 查看表结构:DESC [db_name.]tb_name
  • 删除表:DROP TABLE [IF EXISTS] tb_name
  • 查看表创建命令:SHOW CREATE TABLE tbl_name
  • 查看表状态:SHOW TABLE STATUS LIKE ‘tbl_name’
  • 查看库中所有表状态:SHOW TABLE STATUS FROM db_name

数据类型

  • 数据类型:
      数据长什么样?
      数据需要多少空间来存放?
  • 系统内置数据类型和用户定义数据类型
  • MySql支持多种列类型:
      数值类型
      日期/时间类型
      字符串(字符)类型
      https://dev.mysql.com/doc/refman/5.5/en/data-types.html
  • 选择正确的数据类型对于获得高性能至关重要,三大原则:
      更小的通常更好,尽量使用可正确存储数据的最小数据类型
      简单就好,简单数据类型的操作通常需要更少的CPU周期
      尽量避免NULL,包含为NULL的列,对MySQL更难优化

数据变型
Linux高级篇--MYSQL数据库基础知识、数据库安装、SQL语句以及数据库和表管理_第1张图片

数据类型

  • 1、整型
tinyint(m)          1个字节范围(-128~127)
smallint(m)         2个字节范围(-32768~32767)
mediumint(m)        3个字节范围(-8388608~8388607)
int(m)              4个字节范围(-2147483648~2147483647)
bigint(m)           8个字节范围(+-9.22*10的18次方)

加了unsigned,则最大值翻倍,如:tinyintunsigned的取值范围为(0~255)
int(m)里的m是表示SELECT查询结果集中的显示宽度,并不影响实际的取值范围,规定了MySQL的一些交互工具(例如MySQL命令行客户端)用来显示字符的个数。对于存储和计算来说,Int(1)和Int(20)是相同的
  BOOL,BOOLEAN:布尔型,是TINYINT(1)的同义词。zero值被视为假,非zero值视为真

  • 2、浮点型(float和double),近似值
      float(m,d) 单精度浮点型8位精度(4字节) m总个数,d小数位
      double(m,d)双精度浮点型16位精度(8字节) m总个数,d小数位
      设一个字段定义为float(6,3),如果插入一个数123.45678,实际数据库里存的是123.457,但总个数还以实际为准,即6位
  • 3、定点数
      在数据库中存放的是精确值,存为十进制
      decimal(m,d) 参数m<65 是总个数,d<30且d   MySQL5.0和更高版本将数字打包保存到一个二进制字符串中(每4个字节存9个数字)。例如,decimal(18,9)小数点两边将各存储9个数字,一共使用9个字节:小数点前的数字用4个字节,小数点后的数字用4个字节,小数点本身占1个字节
      浮点类型在存储同样范围的值时,通常比decimal使用更少的空间。float使用4个字节存储。double占用8个字节
      因为需要额外的空间和计算开销,所以应该尽量只在对小数进行精确计算时才使用decimal——例如存储财务数据。但在数据量比较大的时候,可以考虑使用bigint代替decima
  • 4、字符串(char,varchar,_text)
char(n)         固定长度,最多255个字符
varchar(n)      可变长度,最多65535个字符
tinytext        可变长度,最多255个字符
text            可变长度,最多65535个字符
mediumtext      可变长度,最多2的24次方-1个字符
longtext        可变长度,最多2的32次方-1个字符
BINARY(M)       固定长度,可存二进制或字符,长度为0-M字节
VARBINARY(M)    可变长度,可存二进制或字符,允许长度为0-M字节
内建类型:ENUM枚举, SET集合
  • char和varchar:
      (1)char(n) 若存入字符数小于n,则以空格补于其后,查询之时再将空格去掉。所以char类型存储的字符串末尾不能有空格,varchar不限于此。
      (2)char(n) 固定长度,char(4)不管是存入几个字符,都将占用4个字节,varchar是存入的实际字符数+1个字节(n< n>255),所以varchar(4),存入3个字符将占用4个字节。
      (3)char类型的字符串检索速度要比varchar类型的快
    Linux高级篇--MYSQL数据库基础知识、数据库安装、SQL语句以及数据库和表管理_第2张图片
  • varchar和text:
      (1)varchar可指定n,text不能指定,内部存储varchar是存入的实际字符数+1个字节(n< n>255),text是实际字符数+2个字节。
      (2)text类型不能有默认值
      (3)varchar可直接创建索引,text创建索引要指定前多少个字符。varchar查询速度快于text
  • 5.二进制数据:BLOB
      BLOB和text存储方式不同,TEXT以文本方式存储,英文存储区分大小写,而Blob是以二进制方式存储,不分大小写
      BLOB存储的数据只能整体读出
      TEXT可以指定字符集,BLOB不用指定字符集
  • 6.日期时间类型
date    日期'2008-12-2'
time    时间'12:25:36'
datetime     日期时间'2008-12-2 22:06:44'
timestamp    自动存储记录修改时间
YEAR(2), YEAR(4):年份

timestamp字段里的时间数据会随其他字段修改的时候自动刷新,这个数据类型的字段可以存放这条记录最后被修改的时间

修饰符

  • 所有类型:
NULL                   数据列可包含NULL值
NOT NULL               数据列不允许包含NULL值
DEFAULT                默认值
PRIMARY KEY            主键
UNIQUE KEY             唯一键
CHARACTER SET name     指定一个字符集
  • 数值型
AUTO_INCREMENT         自动递增,适用于整数类型
UNSIGNED               无符号

示例:

CREATE TABLE students (id int UNSIGNED NOT NULL PRIMARY KEY,name VARCHAR(20)NOT NULL,age tinyint UNSIGNED);
DESC students;
CREATE TABLE students2 (id int UNSIGNED NOT NULL ,name VARCHAR(20) NOT NULL,age tinyint UNSIGNED,PRIMARY KEY(id,name));

表操作

  • DROP TABLE [IF EXISTS] ‘tbl_name’;
  • ALTER TABLE ‘tbl_name’
      字段:
        添加字段:add
        ADD col1 data_type[FIRST|AFTER col_name]
        删除字段:drop
        修改字段:
        alter(默认值), change(字段名), modify(字段属性)
      索引:
        添加索引:add index
        删除索引:drop index
      表选项
        修改:
  • 查看表上的索引:SHOW INDEXES FROM [db_name.]tbl_name;
  • 查看帮助:Help ALTER TABLE

示例:修改表

ALTER TABLE students RENAME s1;
ALTER TABLE s1 ADD phone varchar(11) AFTER name;
ALTER TABLE s1 MODIFY phone int;
ALTER TABLE s1 CHANGE COLUMN phone mobile char(11);
ALTER TABLE s1 DROP COLUMN mobile;
Help ALTER TABLE 查看帮助
ALTER TABLE students ADD gender ENUM('m','f')
ALETR TABLE students CHANGE id sid int UNSIGNED NOT NULL PRIMARY KEY;
ALTER TABLE students ADD UNIQUE KEY(name);
ALTER TABLE students ADD INDEX(age);
DESC students;
SHOW INDEXES FROM students;
ALTER TABLE students DROP age;

DML语句

  • DML: INSERT, DELETE, UPDATE
  • INSERT:
      一次插入一行或多行数据
    语法:
    (1)INSERT [L OW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
      [INTO] tbl_name[(col_name,…)]
      {VALUES | VALUE} ({expr | DEFAULT},…),(…),…
      [ ON DUPLICATE KEY UPDATE 如果重复更新之
      col_name=expr
      [, col_name=expr] … ]
    简化写法:
    INSERT tbl_name[(col1,…)] VALUES (val1,…), (val21,…)
一次性添加一条记录
insert into students (name,phone,sex,age)values('mage','10086','m','30');
一次性添加多条记录
MariaDB [db1]> insert into students (name,phone,sex,age)values('wang','10000','m','20'),('li','111111','m','20');

(2)INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
  [INTO] tbl_name
  SET col_name={expr | DEFAULT}, …
  [ ON DUPLICATE KEY UPDATE
  col_name=expr
  [, col_name=expr] … ]

把其他数据库的表导入数据库中
insert ... select 写法
insert into students(name,phone,sex,age) select name,phone,sex,age from db1.students;
注意:数据类型必须一致

(3)INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
  [INTO] tbl_name[(col_name,…)]
  SELECT …
  [ ON DUPLICATE KEY UPDATE
  col_name=expr
  [, col_name=expr] … ]

把其他数据库的表导入数据库中
insert ... set写法
insert into students set name='han',sex='m';
  • UPDATE:
    UPDATE [LOW_PRIORITY] [IGNORE] table_reference
    SET col_name1={expr1|DEFAULT} [, col_name2={expr2|DEFAULT}] …
    [WHERE where_condition]
    [ORDER BY …]
    [LIMIT row_count]
  • 注意:一定要有限制条件,否则将修改所有行的指定字段
      限制条件:
        WHERE
        LIMIT
update students set sex='f' where id=5;
可同时更改多个字段:
update students set name='li',sex='f' where id=5;
把id为5的字段名字和性别进行更改
  • Mysql选项:-U|–safe-updates| --i-am-a-dummy
数据库修改时一定要添加限制条件,否则将修改所有行的指定字段
为了避免出现忘记添加限制条件,可以使用以下选项:
在登录数据库时,加上-U选项,即mysql -U -uroot -p
加上-U选项后,如果在数据库中执行命令忘记添加限制条件时,会出现错误信息
MariaDB [db2]> update students set name='li',sex='f';
ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column

为了使用方便,实现不输入-U选项也会有错误提示
在数据库客户端配置文件mysql语句块中添加safe-updates
vim /etc/my.cnf.d/mysql-clients.cnf
[mysql]
safe-updates
  • DELETE:
  • DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name
    [WHERE where_condition]
    [ORDER BY …]
    [LIMIT row_count]
      可先排序再指定删除的行数
  • 注意:一定要有限制条件,否则将清空表中的所有数据
      限制条件:
        WHERE
        LIMIT
  • TRUNCATE TABLE tbl_name; 清空表
    -U选项也适用与delete命令,可以避免出现忘记条件限制删除全部记录的情况

DQL语句

  • SELECT语法:
      [ALL | DISTINCT | DISTINCTROW ]
      [SQL_CACHE | SQL_NO_CACHE]
      select_expr[, select_expr…]
      [FROM table_references
      [WHERE where_condition]
      [GROUP BY {col_name| expr | position}
      [ASC | DESC], … [WITH ROLLUP]]
      [HAVING where_condition]
      [ORDER BY {col_name| expr | position}
      [ASC | DESC], …]
      [LIMIT {[offset,] row_count| row_countOFFSET offset}]
      [FOR UPDATE | LOCK IN SHARE MODE]

SELECT相关用法

  • 字段显示可以使用别名:
    col1 AS alias1, col2 AS alias2, …
select stuid as 学员编号,name 姓名,age 年龄 from students;  把关键字段以中文显示,而且字段显示的前后顺序可以自定义
+--------------+---------------+--------+
| 学员编号      | 姓名          | 年龄   |
+--------------+---------------+--------+
|            1 | Shi Zhongyu   |     22 |
|            2 | Shi Potian    |     22 |
|            3 | Xie Yanke     |     53 |
|            4 | Ding Dian     |     32 |
|            5 | Yu Yutong     |     26 |
|            6 | Shi Qing      |     46 |
+--------------+---------------+--------+
  • WHERE子句:指明过滤条件以实现“选择”的功能:
    过滤条件:布尔型表达式
    算术操作符:+, -, *, /, %
    比较操作符:=,<=>(相等或都为空), <>, !=(非标准SQL), >, >=, <, <=
    BETWEEN min_num AND max_num
    IN (element1, element2, …)
    IS NULL
    IS NOT NULL
  • DISTINCT 去除重复列
      SELECT DISTINCT gender FROM students;
  • LIKE:
      %: 任意长度的任意字符
      _:任意单个字符
  • RLIKE:正则表达式,索引失效,不建议使用
  • REGEXP:匹配字符串可用正则表达式书写模式,同上
  • 逻辑操作符:
      NOT
      AND
      OR
      XOR
  • GROUP:根据指定的条件把查询结果进行“分组”以用于做“聚合”运算
    avg(), max(), min(), count(), sum()
    HAVING: 对分组聚合运算后的结果指定过滤条件
  • ORDER BY: 根据指定的字段对查询结果进行排序
    升序:ASC
    降序:DESC
  • LIMIT [[offset,]row_count]:对查询的结果进行输出行数数量限制
  • 对查询结果中的数据请求施加“锁”
    FOR UPDATE: 写锁,独占或排它锁,只有一个读和写
    LOCK IN SHARE MODE: 读锁,共享锁,同时多个读

示例:

比较操作符
select * from students where classid=1;  挑选出students表中班级编号为1的学员
注意:这里表名大小写敏感,书写时要与表名一致;而字段名则大小写不敏感,不用与表中字段名一致,但为了使得命令规范化,尽量使其与原内容格式保持一致。
select * from students where age > 30 and age <50;

between  and 命令:
select * from students where age between 30 and  50;
挑出students表中年龄大于30小于50岁的学员
这两种写法类似,但是要注意,between and命令表示闭区间,包括30和50;而大于和小于号则是开区间,并不包括30和50

in命令:
select * from students where classid in (1,2,3);

IS NULL和IS NOT NULL命令:
select * from students where teacherid is null;
select * from students where teacherid is not null;

distinct  去除重复列
select distinct  classid from students ;

like:支持通配符
%  匹配任意长度的字符
select * from students where name like 's%';  选择以s开头的学员
select * from students where name like '%o';  选择以o结尾的学员
建议使用左前缀写法,即's%',因为在性能优化方面,右后缀写法'%o'和包含写法'%o%'会带来性能的影响

rlike和regexp:支持正则表达式
select * from students where name rlike '^s';
这种写法不推荐使用,因为这种写法性能更差

order by:排序
select * from students order by age;  以年龄排序,默认正序排序
select * from students order by age desc;   倒序排序
默认排序是根据排序规则进行排序的
show character set;  查看默认排序规则
简体中文  gb2312

LIMIT [[offset,]row_count]: 对显示结果进行行数数量限制
select * from students limit 3;
limit 2,3    2是指偏移量,3是指显示行数
select * from students order by age limit 2,3;   是指跳过前两个,显示后三个

group:分组,分类别
count() 函数  返回select命令中检索到的行中非null值的数目
注意()内的字段的值为非空字段,即该字段的值中不能出现null,否则将不能查询出准确的值
MariaDB [hellodb]> select count(*) from students ;
+----------+
| count(*) |
+----------+
|       25 |
+----------+
1 row in set (0.00 sec)

select classid,count(*) from students group by classid ;
统计每个班级中的人数,即以班级id为分组,统计每个班级中的总人数

一旦做分组,select 后跟的语句必须是两种内容:第一,要写分组本身,第二,要跟聚合函数,即做汇总的数据,如:最大值max,最小值min,平均值avg等
如:
select classid,min(age) from students group by classid ;
统计每个班级中最小年龄的人

先分组再做过滤
注意:一旦分组,如果要在分组后再做条件过滤,则不能使用where,而是要使用having
select classid,avg(age) from students group by classid having classid in (1,2);
统计students表中1班2班的平均年龄

select classid,avg(age) from students where gender = 'm' group by classid having classid in (1,2);
统计1班2班中男生的平均年龄
注意:如果先过滤后分组,则还是使用where

对多个字段分组:
select classid,gender,count(*) from students group by classid,gender;
统计每个班级中的男生女生分别有几个,即以班级作为分组后,再以性别作为分组进行统计

select * from students where birth between '1988-01-01 00:00:00' and '1998-12-31 00:00:00';
从student表中查询出生日期在1988年到1998年的人

课后练习:
导入hellodb.sql生成数据库
(1) 在students表中,查询年龄大于25岁,且为男性的同学的名字和年龄
select * from students where age > 25 and gender='M';
(2) 以ClassID为分组依据,显示每组的平均年龄
select avg(age) from students group by classid;
(3) 显示第2题中平均年龄大于30的分组及平均年龄
select classid,avg(age) from students group by classid having avg(age) > 30;
(4) 显示以L开头的名字的同学的信息

select * from students where name like 'L%';
或select * from students where name rlike '^L';

(5) 显示TeacherID非空的同学的相关信息
select * from students where teacherid is not null;
(6) 以年龄排序后,显示年龄最大的前10位同学的信息
select * from students order by age desc limit 10 ;
(7) 查询年龄大于等于20岁,小于等于25岁的同学的信息

select * from students where age  between 20 and 25;
注意:大于小于号为开区间,不包括20或25.

SQL JOINS
Linux高级篇--MYSQL数据库基础知识、数据库安装、SQL语句以及数据库和表管理_第3张图片

多表查询

  • 交叉连接:笛卡尔乘积
  • 内连接:
      等值连接:让表之间的字段以“等值”建立连接关系;
      不等值连接
      自然连接:去掉重复列的等值连接
      自连接
  • 外连接:
      左外连接:
        FROM tb1 LEFT JOIN tb2 ON tb1.col=tb2.col
      右外连接
        FROM tb1 RIGHT JOIN tb2 ON tb1.col=tb2.col
  • 子查询:在查询语句嵌套着查询语句,性能较差
      基于某语句的查询结果再次进行的查询
  • 用在WHERE子句中的子查询:
      用于比较表达式中的子查询;子查询仅能返回单个值
        SELECT Name,AgeFROM students WHERE Age>(SELECT avg(Age) FROM students);
      用于IN中的子查询:子查询应该单键查询并返回一个或多个值从构成列表
        SELECT Name,AgeFROM students WHERE Age IN (SELECT Age FROM teachers);
      用于EXISTS
  • 用于FROM子句中的子查询
      使用格式:SELECT tb_alias.col1,… FROM (SELECT clause) AS tb_aliasWHERE Clause;

示例:

SELECT s.aage,s.ClassIDFROM (SELECT avg(Age) AS aage,ClassIDFROM students WHERE ClassIDIS NOT NULL GROUP BY ClassID) AS s WHERE s.aage>30;
  • 联合查询:UNION
    SELECT Name,AgeFROM students UNION SELECT Name,AgeFROM teachers

课后练习:
导入hellodb.sql,以下操作在students表上执行
1、以ClassID分组,显示每班的同学的人数
select classid,class,numofstu from classes;
2、以Gender分组,显示其年龄之和
select avg(age) from students group by gender;
3、以ClassID分组,显示其平均年龄大于25的班级
select classid,avg(age) from students group by classid having avg(age) > 25;
4、以Gender分组,显示各组中年龄大于25的学员的年龄之和
select gender,sum(age) from students where age > 25 group by gender;
5、显示前5位同学的姓名、课程及成绩

select student_name,course,score from courses as c inner join (select st.name as student_name,courseid,score from scores as sc inner join (select * from students limit 5) as st on st.stuid=sc.stuid )as a on c.courseid=a.courseid;

6、显示其成绩高于80的同学的名称及课程;

select student_name,course,score from courses as c inner join  (select st.name as student_name,courseid,score from scores as sc  inner join (select * from students limit 5) as st  on st.stuid=sc.stuid group by name)as a  on c.courseid=a.courseid  having score > 80;

7、求前8位同学每位同学自己两门课的平均成绩,并按降序排列

select st.name as student_name,avg(score) as sc_avg from students as st inner join scores as sc on st.stuid=sc.stuid group by st.stuid order by sc_avg desc;

8、显示每门课程课程名称及学习了这门课的同学的个数

select c.course,count(stuid) as studnet_count  from scores as s left join courses as c on s.courseid=c.courseid group by s.courseid;

9、显示其年龄大于平均年龄的同学的名字
select name from students where age > (select avg(age) from students);
10、显示其学习的课程为第1、2,4或第7门课的同学的名字

select name from students as st inner join (select distinct  sc.stuid  from scores as sc inner join (select * from courses where courseid in(1,2,4) or courseid in (7)) as c on sc.courseid=c.courseid) as a on st.stuid=a.stuid;

11、显示其成员数最少为3个的班级的同学中年龄大于同班同学平均年龄的同学

select student.name,student.age,student.classid,second.avg_age from (select students.name as name ,students.age as age,students.classid as classid from students left join (select count(name) as num,classid as classid from students group by classid having num>=3) as first on first.classid=students.classid) as student,(select avg(age) as avg_age,classid as classid from students group by classid) as  second where student.age>second.avg_age and student.classid=second.classid;

12、统计各班级中年龄大于全校同学平均年龄的同学
select name,classid,age from students where age > (select avg(age) from students);

视图

  • 视图:VIEW,虚表,保存有实表的查询结果
    例如,把内连接或外连接查询出来的结果定义为视图,使用该视图可直接查询出内连接或外连接查询出的结果,类似于给查询结果定义一个别名
    但是,视图本身不保存查询出来的数据,只显示查询出来的结果,数据来自于实际的表
  • 创建方法:
      CREATE VIEW view_name[(column_list)]
        AS select_statement
        [WITH [CASCADED | LOCAL] CHECK OPTION]
  • 查看视图定义:SHOW CREATE VIEW view_name
  • 删除视图:
      DROP VIEW [IF EXISTS]
        view_name[, view_name] …
        [RESTRICT | CASCADE]
  • 视图中的数据事实上存储于“基表”中,因此,其修改操作也会针对基表实现;其修改操作受基表限制

你可能感兴趣的:(Linux高级篇--MYSQL数据库基础知识、数据库安装、SQL语句以及数据库和表管理)