目录
第一章 NoSQL
1.1 什么是NoSQL
NoSQL(Not Only SQL)即不仅仅是SQL,泛指非关系型的数据库,它可以作为关系型数据库的良好补充。随着互联网web2.0网站的兴起,非关系型的数据库现在成了一个极其热门的新领域,非关系数据库产品的发展非常迅速。
1.2 NoSQL的类别
键值(key-value)存储数据库
说明:这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特定的数据。
Key/Value模型对于IT系统来说优势在于简单、易部署。
应用:内容缓存,主要用于处理大量数据的高访问负载。
产品:Tokyo Cabinet/Tyrant、==Redis==、Voldemort、Berkeley DB。
优势:快速查询。
劣势:存储数据的结构化较低。
列存储数据库
说明:这部分数据库通常是用来应对分布式存储的海量数据。键仍然存在,但是它们的特点是指向了多个列,这些列是由列家族来安排的。
应用:分布式文件系统。
产品:Cassandra,==HBase==,Riak。
优势:查找速度快,可扩展性强,更容易进行分布式扩展。
劣势:功能较低,具有局限性。
文档型数据库
说明:该类型的数据模型 是版本化的文档,半结构化的文档以特定的格式存储,如JSON。文档型数据库可以看作是键值数据库的升级版,允许之间嵌套键值。而且文档型数据库比键值数据库的查询效率更高。
应用:Web应用。
产品:CouchDB,==MongoDB==。
优势:查询效率较高。
劣势:数据结构复杂,缺乏统一查询语法。
图形数据库
说明:图形结构的数据库同其他行列以及刚性结构的SQL数据库不同,它是使用灵活的图形模型,并且能够扩展到多个服务器上。NoSQL数据库没有标准的查询语言(SQL),因此进行数据库查询需要制定数据模型。许多NoSQL数据库都有REST格式的数据接口或者查询API。
应用:社交网络。
产品: ==Neo4j==,InfoGrid,Infinite Graph。
优势:利用图结构相关算法。
劣势:需要对整个图做计算才能得出结果,不容易做分布式的集群方案。
1.3 NoSQL适应场景
1、数据模型比较简单
2、需要灵活性更强的IT系统
3、对数据库性能要求较高
4、不需要高度的数据一致性
5、对于给定的key,比较容易映射出复杂的关系和环境
6、取最新的数据(排行)
7、数据缓存
1.4 在分布式数据库中CAP原理
1.4.1 传统的ACID是什么
关系型数据库遵循==ACID==规则,事务在英文中是transaction,和现实世界中的交易很类似,它有如下四个特性:
-
A (Atomicity) 原子性
指事务里的所有操作要么都成功,要么都失败。事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。
-
C (Consistency) 一致性
指数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。
-
I (Isolation) 隔离性
指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。
-
D (Durability) 持久性
是指一旦事务提交后,它所做的修改将会永久的保存在数据库中,即使出现宕机也不会丢失。
1.4.2 CAP
C 强一致性
A 可用性
P 分区容错性
CAP 理论是指在分布式存储系统中,最多只能实现上述两点。由于当前的网络硬件存在延迟丢包等问题,所以分区容忍性是我们必须要实现的。所以我们只能在一致性和可用性之间进行权衡,没有任何的SQL系统能够兼顾这三点。
CA 传统sql数据库
AP 大多数网站架构的选择
CP nosql数据库
注意:在做分布式架构的时候必须做出取舍。==一致性和可用性之间取一个平衡==。对于大多数web应用,其实并不需要强一致性。因此牺牲C换取P,这是目前分布式数据库产品的方向。
CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。
因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三 大类:
-
==CA== - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
-
==CP== - 满足一致性,分区容忍性的系统,通常性能不是特别高。
-
==AP== - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。
1.5 什么是BASE
BASE 是为了解决关系型数据库强一致性引起的问题而导致可用性降低而提出的解决方案.
基本可用(==B==asically ==A==vailable) 软状态(==S==oft state) 最终一致(==E==ventually consistent)
它的思想是通过让系统放松对某一时刻数据一致性的要求来换取系统整体伸缩性和性能上改观。
第二章 Redis介绍及安装和MySql的安装和部署
2.1 Redis概述
2.1.1 什么是Redis
2008年,意大利的一家创业公司Merzia推出了一款基于MySQL的网站实时统计系统LLOOGG,然而没过多久该公司的创始人 Salvatore Sanfilippo便开始对MySQL的性能感到失望,于是他决定亲自为LLOOGG量身定做一个数据库,并于2009年开发完成,这个数据库就是Redis。不过Salvatore Sanfilippo并不满足只将Redis用于LLOOGG这一款产品,而是希望更多的人使用它,于是在同一年Salvatore Sanfilippo将Redis开源发布,并开始和Redis的另一名主要的代码贡献者Pieter Noordhuis一起继续着Redis的开发,直到今天。
Salvatore Sanfilippo自己也没有想到,短短的几年时间,Redis就拥有了庞大的用户群体。Hacker News在2012年发布了一份数据库的使用情况调查,结果显示有近12%的公司在使用Redis。国内如新浪微博、街旁网、知乎,国外如GitHub、Stack Overflow、Flickr、暴雪和Instagram,都是Redis的用户。
VMware公司从2010年开始赞助Redis的开发, Salvatore Sanfilippo和Pieter Noordhuis也分别在3月和5月加入VMware,全职开发Redis。【本部分内容取自《REDIS入门指南》】
Redis(==RE==mote ==D== ==I==ctionary ==S==erver 远程字典服务器),是完全开源免费的,用C语言编写的,遵守BSD协议,是一个高性能的(key/value)分布式内存数据库,基于内存运行,并支持持久化。是当前比较热门的NOSQL数据库之一,也被人们称之为数据机构服务器。
他提供了很多键值数据类型以用来适应不同场景下的存储需求,在目前Redis所支持的数据类型包括:
-
字符串类型
-
散列类型
-
列表类型
-
集合类型
-
有序集合类型
-
坐标类型
学习参考网站:Redis 教程 | 菜鸟教程
2.1.2 Redis能干什么
-
内存存储和持久化:redis支持异步将内存中的数据写入到磁盘中,同时不影响继续服务
-
取最新N个数据的操作,可以将排行或者指定信息保存在Redis集合容器内
-
模拟类似于HttpSession(会话对象)这种需要设定过期时间的功能
-
定时器 计数器
-
消息的订阅和消息的发布(消息队列 主从配置)
2.1.3 Redis的特点
-
性能非常高:Redis读取速度 11W次/s 写入速度 8W次/s
-
非常丰富的数据类型 :String List Hash Set ZSet等等数据类型操作
-
原子性:Redis内所有操作都是原子性的,意味着要么成功执行,要么失败完全不执行。单个操作是原子性的,多个操作也支持事务。
-
数据持久化:可以将内存中的数据保存在磁盘内,重启的时候可以加载进行使用
-
其他:Redis还支持publish/subscribe 通知,key值生命周期的管理,提供了目前主流编程语言的API接口
2.1.4 如何获取
https://redis.io http://www.redis.cn
2.2 Redis的安装
2.2.1本地安装
PS:做好镜像快照
#步骤1:访问官网 https://redis.io/ #步骤2:选择本地安装 GET STARTED ====> install ====> Install from source #步骤3:下载 # >> wget https://download.redis.io/redis-stable.tar.gz #步骤4:解tar # >> tar -xzvf redis-stable.tar.gz #步骤5:编译器的安装 # >> make # >> make install #步骤6:安装CC控件 # >> dnf install gcc* #步骤7:再次编译安装 # >> make install #步骤8:再次发生问题需要找到README.md配置文件 找到 make malloc = libc # >> make MALLOC = libc #步骤9:再次编译安装 # >> make install 如果提示为: Hint: It's a good idea to run 'make test' ;) INSTALL redis-server INSTALL redis-benchmark INSTALL redis-cli 意味着安装成功。 #步骤10:开启服务 # >> redis-server
2.3 MySql描述
仅仅是一个产品,Oracle旗下的小型数据库。广泛应用在中小型项目中,特征体积小速度快整体成本低。尤其是开源,所以很多中小型项目为了降低成本纷纷选用MySql作为数控存储介质。
2.4 MySql的特征
1.底层语言使用C、C++编写的。并且使用多种编译器进行测试,以确保源码的可移植性。
2.支持市面上所有的操作系统。
3.为编程语言提供了API,编程语言包含但不限于C、C++、C#、Delphi、Eiffel、Java、Perl、PHP、Python、Ruby和Tcl等。
4.支持多线程,充分利用CPU资源,支持多用户访问。
5.出色的Sql算法优化,能够更有效的提高查询效率。
6.除了常规的安装外,Mysql还能作为嵌入式嵌入在其他软件内。
7.提供了多语言支持。
8.提供了TCP/IP ODBC JDBC等多种数据库连接机制。
9.提供用于管理,检查,优化数据库操作的管理工具。
10.庞大的算法加持,可以轻松处理千万级别记录的内容。
2.5 获取方式
四个版本
Alpha版:开发版,公司内部使用。
Beta版: 体验版,开发完成之后,供用户体验。
RC版: 候选班,正式版发布之前,诞生的小版本。
GA版: 正式发布版本。
MySql官方网站 http://www.mysql.com
安装包 源码包 二进制包 发行光盘获取
我们使用的版本
MySQL Community Server 社区版本,开源免费。(不提供官方支持)。
其他分支版本:
MySQL Enterprise Edition 企业版本,需付费,可以试用 30 天。
MySQL Cluster 集群版,开源免费。可将几个 MySQL Server 封装成一个 Server。
MySQL Cluster CGE 高级集群版,需付费。
2.6 MySql环境安装
操作系统版本信息 :rhel-baseos-9.1-x86_64 >>>>> 安装过程详见录屏
插入光盘>>>
输入命令 df -h 可以显示 默认/dev/sr0文件为光盘文件
输入命令 mount -o ro /dev/sr0 /media 进行手动挂载
进入 cd /etc/yum.repos.d 目录(初始状态是没有这两个文件的)
编辑并配置文件 vim yum.repo
[BaseOS] name=baseos yum enabled=1 baseurl=file:///media/BaseOS gpgcheck=0 [AppStream] name=app yum enabled=1 baseurl=file:///media/AppStream gpgcheck=0
清空yum缓存
yum clean all
创建yum缓存仓库
yum makecache
查看列表
yum repolist
2.7 MySql正式安装
Mysql官网====>DOWNLOADS====>MySQL Community (GPL) Downloads ====>Download Archives下载档案====>MySQL Community Server MySql社区服务器====>MySQL Downloads
下载
wget https://cdn.mysql.com/archives/mysql-8.0/mysql-8.0.34-1.el9.x86_64.rpm-bundle.tar
解tar
tar xvf mysql-8.0.34-1.el9.x86_64.rpm-bundle.tar
安装
dnf localinstall mysql-community-server-8.0.34-1.el9.x86_64.rpm mysql-community-client-8.0.34-1.el9.x86_64.rpm mysql-community-common-8.0.34-1.el9.x86_64.rpm mysql-community-icu-data-files-8.0.34-1.el9.x86_64.rpm mysql-community-client-plugins-8.0.34-1.el9.x86_64.rpm mysql-community-libs-8.0.34-1.el9.x86_64.rpm
提示安装完毕
已安装: mysql-community-client-8.0.34-1.el9.x86_64 mysql-community-client-plugins-8.0.34-1.el9.x86_64 mysql-community-common-8.0.34-1.el9.x86_64 mysql-community-icu-data-files-8.0.34-1.el9.x86_64 mysql-community-libs-8.0.34-1.el9.x86_64 mysql-community-server-8.0.34-1.el9.x86_64
2.8部署和启动
2.8.1启动服务
systemctl start mysqld
2.8.2检查启动状况
systemctl status mysqld
2.8.3查看日志以获取初始登录密码
grep password /var/log/mysqld.log
2.8.4复制密码保存为首次登录做准备
mysql -uroot -p .....初始密码.....
2.8.5进入产品后,修改登录密码
语法: ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码'; (字母+数字+特殊符号)
ALTER USER 'root'@'localhost' IDENTIFIED BY 'Openlab123!';
2.5.6使用远程管理工具链接Mysql数据库
若想链接Mysql需要解决四个问题
1 目标地址 ===> 直接查询即可
2 端口号 ===> 3306
3 防火墙关闭卸载
systemctl stop firewalld.service #关闭 systemctl disable firewalld.service #卸载
4授权 mysql数据库root用户的权 127.0.0.1 ====> *
先登录进入Mysql
进入 mysql 子库
use mysql;
执行修改命令
update user set host='%' where user='root';
刷新权限管理
flush privileges;
再次退出
exit;
####
安装并激活Navicat 15 https://zhuanlan.zhihu.com/p/666867535
第三章 MySQL库表操作
3.1 SQL语句基础(SQL命令)
3.1.1 SQL简介
SQL:结构化查询语言(Structured Query Language),在关系型数据库上执行数据操作,数据检索以及数据维护的标准化语言。使用SQL语句,程序员和数据库管理员可以完成如下的任务:
1 改变数据库的结构
2 更改系统的安全设置
3 增加用户对数据库或表的许可权限
4 在数据库中检索需要的信息
5 对数据库的信息进行更新 备份 还原
综上所述 :想要使用Mysql数据库 必须要学习Sql语言。
3.1.2 SQL语句的分类
MySQL致力于支持全套ANSI/ISO SQL标准。在MySQL数据库中,SQL语句主要可以划分为以下几类:
1 DDL(Data Definition Language): 数据定义语言。定义对数据库对象(库、表、列、索引)的操作。
关键字:CREATE、DROP、ALTER、RENAME、 TRUNCATE等。
2 DML(Data Manipulation Language):数据操作语言。定义对数据库记录的操作。
关键字:INSERT、DELETE、UPDATE等。
3 DCL(Data Control Language):数据控制语言。定义对数据库、表、字段、用户的访问权限和安全级别。
关键字:GRANT、REVOKE等。
4 DQL(Data Query Language):数据查询语言。检索并获取数据。
关键字: SELECT。
3.1.3 SQL语句的书写规范
在数据库系统中,SQL语句不区分大小写(建议用大写) 。
字符串常量区分大小写。
SQL语句支持单行||多行书写,但必须以;结尾。
关键字||词汇不能跨行书写。
支持空格或缩进以提升语句的可读性。
子语句通畅位于独立行,便于编辑,提高可读性。
3.2 数据库操作
1、查看 SHOW DATABASES [LIKE wild] ; 功能:列出Mysql主机上的狭义数据库。 Mysql自带数据库(系统库): information_schema:主要存储了系统中的一些数据库对象信息,如用户信息,列信息,权限信息,字符集信息,分区信息等(数据字典) performance_schema:主要存储了数据库服务器的性能参数 mysql:主要存储了系统的用户权限信息和帮助文档 sys:5.7后新增产物,information_schema和performance_schema的结合体,并以视图形式显示出来的,查询出更加令人容易理解的数据。 原则: 不轻易访问,不轻易修改,不轻易删除!! 2、自建库 创建个人数据库 语法 CREATE DATABASE IF NOT EXISTS 数据库名; CREATE DATABASE IF NOT EXISTS MySchool_db; 一个数据库(微观)是由 表 视图 函数 查询 备份所构成 重中之重是 表 3、切换数据库 使用USE 关键字进行切换 语法 : USE 数据库名; 作用:指定数据库为我们的默认数据库,用于后期建表或其他使用。 其他: 1 查看当前访问的数据库 SELECT DATABASE(); 2 查看当前数据库服务器版本 SELECT VERSION(); 3 查看当前登录用户 SELECT USER(); 4 查看用户详细信息 SELECT User,Host [,PassWord] FROM mysql.user; 4、删库 DROP DATABASE [IF EXISTS] 数据库名; 功能:删除当前数据库>>>里面的结构 数据 全都没了(慎用)
3.3 MySQL字符集
MySQL字符集包括 基字符集(CHARACTER) && 校对规则 (COLLATION)这两个概念:
latin1支持西欧字符、希腊字符等 gbk支持中文简体字符 big5支持中文繁体字符 utf8几乎支持世界所有国家的字符。 utf8mb4是真正意义上的utf-8
可以使用命令 SHOW VARIABLES like 'character%'; 查看当前数据库默认的字符集
character_set_client MySQL 客户机字符集。 character_set_connection 数据通信链路字符集,当MySQL客户机向服务器发送请求时,请求数据以 该字符集进行编码。 character_set_database 数据库字符集。
3.3.1 utf8和utf8mb4的区别
MySQL在5.5.3之后增加了这个utf8mb4的编码,mb4就是most bytes 4的意思,专门用来兼容四字节的unicode。好在utf8mb4是utf8的超集,除了将编码改为utf8mb4外不需要做其他转换。当然,为了节省空间,一般情况下使用utf8也就够了。
既然utf8能够存下大部分中文汉字,那为什么还要使用utf8mb4呢? 原来mysql支持的 utf8 编码最大字符长度为 3 字节,如果遇到 4 字节的宽字符就会插入异常了。三个字节的 UTF-8 最大能编码的 Unicode 字符是 0xffff,也就是 Unicode 中的基本多文种平面(BMP)。也就是说,任何不在基本多文本平面的 Unicode字符,都无法使用 Mysql 的 utf8 字符集存储。包括 Emoji 表情(Emoji 是一种特殊的 Unicode 编码,常见于 ios 和 android 手机上),和很多不常用的汉字,以及任何新增的 Unicode 字符,如表情等等(utf8的缺点)。
因此在8.0之后,建议大家使用utf8mb4这种编码。
3.4 数据库设计与数据库对象
3.4.1数据库设计的步骤
为啥要进行数据库设计
糟糕的数据库设计 VS 成熟的数据库设计
数据冗余,存储空间造成浪费 VS 节省数据的存储空间
内存 日志 空间浪费 VS 完整性高,数据原子性强
数据的更新和插入时时刻刻伴随着风险和异常 VS 方便进行数据库应用和系统开发
那么如何进行数据库设计??
步骤:
1.需求分析阶段:旨在分析客户的业务和数据处理的需求
2.概要设计阶段:设计出数据库的E-R模型图,确认需求信息的正确和完整性
3.详细设计阶段:运用数据库三大范式越泽,规范审核数据库结构,形成数据库模型图
4.代码编写阶段:物理实现数据库,代码实现应用
5.测试阶段: 实践||实验
6.备份还原阶段:...
3.4.2 如何绘制数据库E-R图
例题:酒店管理系统的基本功能:
1.收集信息:系统有关人员进行交流、座谈,充分了解用户需求,理解数据库需要完成的任务
-
旅客办理入住手续:后台数据库需要存放入住客人的信息和客房信息
-
客房信息:后台数据库需要存放客房的相关信息,如客房号、床位数、价格等
-
客房管理信息:后台数据库需要保存客房类型信息和客房当前状态信息
2.标识出实体:数据库要管理的关键对象或实体内容,实体通常情况下 是一个名词
-
客人:入住酒店的旅客。办理入职手续时,需填写用户信息。
-
客房:酒店为客人提供休息的住所。
3.标识出每个实体的属性:
-
客人属性:编号 姓名 身份证.....
-
客房属性:编号 名称 床位 状态 类型....
4.标识出实体和实体之间的关系:
实体和实体之间的关系 通常用动词去描述
入住 关系
客房和客人之间 存在主从关系 ====> 客房是主1 客人是从N
1对N关系 ====> 被引用 引用关系
从设计角度上来说 就是 N个人可以住一个房子
客房被客人引用了 >>>> 客人引用了客房
绘制E-R 实体关系图(三要素)
符号 | 含义 |
---|---|
矩形 | 实体,一般是名词 |
椭圆形 | 实体,一般是名词 |
菱形 | 关系,一般是动词 |
关系型数据库常见映射基数
转化E-R图形成数据库模型图
1 将各实体转化为对应的各表,将各属性对应成为各表的列。
2 标识出每个表的主键列(非空+唯一),一张表有且只有一个主键列。
3 在表之间建立主外键,形成引用被引用关系。
3.4.3使用三大范式实现数据库设计规范化
为什么要进行数据规范化设计
缺点:
-
信息重复
-
更新异常
-
插入异常_无法正确表示信息
-
删除异常_丢失有效信息
三大范式原则:
第一范式 (1st NF)
-
第一范式的目标是确保每列的原子性
-
如果每列都是不可再分的最小数据单元(也称为最小的原子单元),则满足第一范式(1NF)
第二范式(2st NF)
-
第二范式要求每个表只描述一件事情
第三范式 (3st NF)
-
如果一个关系满足2NF,并且除了主键以外的其他列都不传递依赖于主键列,则满足第三范式(3NF)
规范化的酒店管理系统E-R图
规范化的酒店管理系统数据库模型图
后面就可以开心的完成建表的操作了
3.4.5 课后练习题
某学校要设计一个数据库,学校的业务规则概括如下:
-
学校内班级若干,每个班级内又有学生若干。
-
学校开设课程若干,只有某些特定的班级能上指定的课程。
-
学生选修某些课程,但是在自身班级下的课程是必修。
-
学校定期组织考试,成绩囊括所有学生所有课程的考试成绩。
要求根据上述需求,完成E-R图的构建,并通过三大范式的规范设计出数据库模型图。
解答
实体 系 科目 学生 成绩 属性 系:系编号(PK) 系名称 科目:科目编号(PK) 科目名称 学习时长 系编号 学生:学号(PK) 密码 姓名 性别 系编号 联系电话 生日 邮箱 身份证号码 住址 成绩:学号(FK) 科目号(FK) 考试日期 考试成绩 关系 1系>>>N学生 主从关系 1系>>>N科目 1学生>>>N成绩 1科目>>>N成绩 =========================> N学生<<<>>>N科目 1:建库 MySchool_db CREATE DATABASE Myschool_db; 2:建表(先主后从) 2.1创建年级表 CREATE TABLE grade( GradeID INT NOT NULL AUTO_INCREMENT COMMENT '年级编号', GradeName VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '年级名称', PRIMARY KEY (GradeID) ) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci; 2.2创建科目表 DROP TABLE IF EXISTS subject; CREATE TABLE subject ( SubjectNo int NOT NULL AUTO_INCREMENT COMMENT '课程编号', SubjectName varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '课程名称', ClassHour int NULL DEFAULT NULL COMMENT '学时', GradeID int NULL DEFAULT NULL COMMENT '年级编号', PRIMARY KEY (SubjectNo) ) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci 2.3创建学生表 DROP TABLE IF EXISTS student; CREATE TABLE student ( StudentNo int(0) NOT NULL COMMENT '学号', LoginPwd varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, StudentName varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '学生姓名', Sex tinyint(1) NULL DEFAULT NULL COMMENT '性别,取值0或1', GradeId int(0) NULL DEFAULT NULL COMMENT '年级编号', Phone varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系电话,允许为空,即可选输入', Address varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '地址,允许为空,即可选输入', BornDate datetime(0) NULL DEFAULT NULL COMMENT '出生时间', Email varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱账号,允许为空,即可选输入', IdentityCard varchar(18) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '身份证号', PRIMARY KEY (StudentNo) USING BTREE, UNIQUE INDEX IdentityCard(IdentityCard) USING BTREE, INDEX Email(Email) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci; 2.4创建成绩表 CREATE TABLE `result` ( `StudentNo` int(0) NOT NULL COMMENT '学号', `SubjectNo` int(0) NOT NULL COMMENT '课程编号', `ExamDate` datetime(0) NOT NULL COMMENT '考试日期', `StudentResult` int(0) NOT NULL COMMENT '考试成绩', INDEX `SubjectNo`(`SubjectNo`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci >>>>>> 为subject表添加外键约束 ALTER TABLE subject ADD CONSTRAINT fk_subgra FOREIGN KEY (GradeID) REFERENCES grade (GradeID); 为student表添加外键约束 ALTER TABLE student ADD CONSTRAINT fk_stugra FOREIGN KEY (GradeID) REFERENCES grade (GradeID);
3.5 表的基本操作
3.5.1 创建表
建表的语法
标准的建表(table)语法(列定义之间以英文逗号,隔开): 数据表的每行称为一条记录(record),每一列称为一个字段(field): 主键(字段)列:唯一标识某一行的列: CREATE TABLE 表名( 列名(字段名) 类型, 列名(字段名) 类型, 列名(字段名) 类型, 列名(字段名) 类型, 列名(字段名) 类型 ) ENGINE = 存储结构; 表名采用大驼峰命名如 >>> Students Subject StudentResult 表名采用小驼峰命名如 >>> studentName subjectName resultDate
3.5.2 表物理存储结构
MyISAM || InnoDB(默认) 存储列相关信息,描述表结构文件,字段长度等 如果采用共存储模式的,数据信息和索引信息都存储在ibdata1中, 如果采用分区存储,还会有一个t.par文件(用来存储分区信息)。
3.5.3 数据类型
在mysql中,常用数据类型有三种:1、文本类型 2、数字类型 3、日期/时间类型
文本类型类型:
数据类型 | 描述 |
---|---|
CHAR(size) | 保存固定长度的字符串(可包含字母、数字以及特殊字 符)。在括号中指定字符串的长度。最多 255 个字符。 |
VARCHAR(size) | 保存可变长度的字符串(可包含字母、数字以及特殊字 符)。在括号中指定字符串的最大长度。最多 255 个字 符。如果size>255,则类型会自动转换为TEXT类型。 |
TEXT | 存放最大长度为 65,535 个字符的字符串。 |
TINYTEXT | 存放最大长度为 255 个字符的字符串。 |
MEDIUMTEXT | 存放最大长度为 16,777,215 个字符的字符串。 |
LONGTEXT | 存放最大长度为 4,294,967,295 个字符的字符串。 |
BLOB | 用于 BLOBs (Binary Large OBjects)。存放最多 65,535 字节的数据。 |
MEDIUMBLOB | 用于 BLOBs (Binary Large OBjects)。存放最多 16,777,215 字节的数据。 |
LONGBLOB | 用于 BLOBs (Binary Large OBjects)。存放最多 4,294,967,295 字节的数据。 |
ENUM | 枚举类型 |
数字类型:
数据类型 | 描述 |
---|---|
TINYINT(size) | -128 到 127 常规。 0 到 255 无符号*。在括号中规定最 大位数 |
SMALLINT(size) | -32768 到 32767 常规。 0 到 65535 无符号*。在括号中 规定最大位数。 |
MEDIUMINT(size) | -8388608 到 8388607 普通。 0 到 16777215 无符号*。在 括号中规定最大位数。 |
INT(size) | -2147483648 到 2147483647 常规。 0 到 4294967295 无 符号*。在括号中规定最大位数。 |
BIGINT(size) | -9223372036854775808 到 9223372036854775807 常规。 |
FLOAT(size,d) | 带有浮动小数点的小数字。在括号中规定最大位数。在 d 参数中规定小数点右侧的最大位数。 |
DOUBLE(size,d) | 带有浮动小数点的大数字。在括号中规定最大位数。在 d 参数中规定小数点右侧的最大位数。 |
DECIMAL(size,d) | 作为字符串存储的 DOUBLE 类型,允许固定的小数点。 |
时间\日期类型:
数据类型 | 描述 |
---|---|
DATE() | 日期。格式:YYYY-MM-DD 取值范围 '1000-01-01' <<<>>> '9999-12-31' |
DATETIME() | 日期和时间的组合。格式: YYYY-MM-DD HH:MM:SS 注释:支持的范围是'1000-01-01 00:00:00' <<<>>> '9999-12- 31 23:59:59' |
TIMESTAMP() | 时间戳。 TIMESTAMP 值使用 Unix 纪元('1970-01-01 00:00:00' UTC) 至今的描述来存储。格式: YYYY-MM-DD HH:MM:SS 注释:支持的范围是从 '1970-01-01 00:00:01' UTC 到 '2038-01-09 03:14:07' UTC |
TIME() | 时间。格式: HH:MM:SS 注释:支持的范围是从 '-838:59:59' 到 '838:59:59' |
YEAR() | 2 位或 4 位格式的年。 注释: 4 位格式所允许的值: 1901 到 2155。 2 位格式所允许 的值: 70 到69,表示从 1970 到 2069 |
常用数据类型:
3.5.4 查看表
SHOW命令
语法:
SHOW TABLES [FROM 数据库名] [LIKE wild];
查看表结构:
SHOW COLUMNS FROM 表名
3.5.5 删除表
DROP TABLE [IF EXISTS] 表名
示例:
#创建学生表 CREATE TABLE Students( studentNo INT(5), studentName VARCHAR(50), studentBirth DATE, studentAddress VARCHAR(100), studentTel VARCHAR(11), studentEmail VARCHAR(50) ) ENGINE = InnoDB; #查看表结构 SHOW COLUMNS FROM Students; #删除表 DROP TABLE [IF EXISTS] Student;
3.5.6 修改表的结构
修改列类型 ALTER TABLE 表名 MODIFY 列名 列类型; >>> ALTER TABLE Students MODIFY studentEmail TEXT; 添加列 ALTER TABLE 表名 ADD 列名 列类型; >>> ALTER TABLE Students ADD studentGender CHAR(2); 删除列 ALTER TABLE 表名 DROP 列名; 删除时注意数据完整性 >>> ALTER TABLE Students DROP studentGender; 改列名 ALTER TABLE 表名 CHANGE 旧列名 新列名 列类型; >>> ALTER TABLE Students CHANGE studentEmail studentEma VARCHAR(50); 改表名 ALTER TABLE 表名 RENAME 新表名; RENAME TABLE 表名 TO 新表名;
3.5.7 复制表的结构(考虑到数据问题)
复制表的结构有两种手段 方式1: 在 CREATE TABLE 语句的末尾加入 LIKE 源表; >>> CREATE TABLE Students1 LIKE Students; 方式2: 在 CREATE TABLE 语句末尾添加 SELECT 关键字; >>> CREATE TABLE Students2 SELECT * FROM Students; 方法3: 如果已经有一张表了(结构一定要和源表一样) >>> INSERT INTO 表名 SELECT * FROM 源表;
3.5.8 数据库字典
由 information_schema 数据库负责维护 tables-存放数据库里所有的数据表、以及每个表所在数据库。 schemata-存放数据库里所有的数据库信息 views-存放数据库里所有的视图信息。 columns-存放数据库里所有的列信息。 triggers-存放数据库里所有的触发器。 routines-存放数据库里所有存储过程和函数。 key_column_usage-存放数据库所有的主外键 table_constraints-存放数据库全部约束。 statistics-存放了数据表的索引。
3.5.9 表的约束
是在表上强制执行的数据校验规则。约束主要用于保证数据库的完整性。当表中数据有相互依赖性时,可以保护相关的数据不被删除。大部分数据库支持下面五类完整性约束:
非空约束 NOT NULL 唯一性约束 UNIQUE KEY 主键约束(非空+唯一) PRIMARY KEY 外键约束 FOREIGN KEY 检查约束 CHECK 检查语法 默认值约束 DEFAULT ....... 加入约束的三种时机 1,建表时期加入,直接符在声明的列后。 2,建表时期加入,所有列声明完成后,单独去重新声明列的约束性。 3,建表后加入,语法参考修改列类型语法完成约束的添加。 >>>>>>>> 约束作为数据库对象,存放在系统表中,也有自己的名字 创建约束的时机 在建表的同时创建 建表后创建(修改表) 可定义列级或表级约束 有单列约束和多列约束 定义约束的语法 方式1:列级约束:在定义列的同时定义约束 语法:列定义 约束类型, 方式2:表级约束:在定义了所有列之后定义的约束 语法: 列定义 [CONSTRAINT 约束名] 约束类型(列名) 约束名的取名规则 推荐采用:表名_列名_约束类型简介 方式3:约束可以在创建表时就定义,也可以在创建完后再添加 语法: ALTER TABLE 表名 ADD CONSTRAINT 约束名 约束类型(要约束的列名)
表的约束示例
1、非空约束(NOT NULL) 列级约束,只能使用列级约束语法定义。 确保字段值不允许为空 只能在字段级定义 >>> CREATE TABLE Students( studentNo INT PRIMARY KEY AUTO_INCREMENT, studentName VARCHAR(50) NOT NULL ); 2、唯一约束 唯一性约束条件确保所在的字段或者字段组合不出现重复值 唯一性约束条件的字段允许出现多个NULL 同一张表内可建多个唯一约束 唯一约束可由多列组合而成 建唯一约束时MySQL会为之建立对应的索引。 如果不给唯一约束起名,该唯一约束默认与列名相同。 CREATE TABLE Students( studentNo INT PRIMARY KEY AUTO_INCREMENT, studentName VARCHAR(18) UNIQUE NOT NULL ); 3、主键约束 主键从功能上看相当于非空且唯一 一个表中只允许一个主键 主键是表中唯一确定一行数据的字段 删除表的约束 自动增长和默认值 存储引擎 主键字段可以是单字段或者是多字段的组合 当建立主键约束时,MySQL为主键创建对应的索引 主键约束名总为PRIMARY。 CREATE TABLE tb_student( studentNo INT PRIMARY KEY AUTO_INCREMENT, studentName VARCHAR(18) ) 4、外键约束 外键是构建于一个表的两个字段或者两个表的两个字段之间的关系 外键确保了相关的两个字段的两个关系: 子(从)表外键列的值必须在主表参照列值的范围内,或者为空(也可以加非空约束,强制不允许为空)。 当主表的记录被子表参照时,主表记录不允许被删除。 外键参照的只能是主表主键或者唯一键,保证子表记录可以准确定位到被参照的记录。 格式FOREIGN KEY (外键列名)REFERENCES 主表(参照列) #部门 CREATE TABLE tb_dept( dept_id INT PRIMARY KEY, NAME VARCHAR(18), description VARCHAR(255) ); #员工 CREATE TABLE tb_employee( employee_id INT PRIMARY KEY, NAME VARCHAR(18), gender VARCHAR(10), dept_id INT REFERENCES tb_dept(dept_id), address VARCHAR(255) ); 5、检查约束 #注意检查约束在8.0之前,MySQL默认但不会强制的遵循check约束(写不报错,但是不生效,需要通触发器完成) # 8之后就开始正式支持这个约束了。 create table t3( id int, age int check(age > 18), gender char(1) check(gender in ('M','F')) ); 6、自动增长 auto_increment :自动增长 为新的行产生唯一的标识 一个表只能有一个auto_increment,且该属性必须为主键的一部分。auto_increment的属性可以是任何整数类型 7、默认值 default : 默认值 综合实践: # 默认值 可以使用default关键字设置每一个字段的默认值。 -- 创建一张user表 CREATE TABLE User( id INT(11) NOT NULL AUTO_INCREMENT COMMENT 'id', name VARCHAR(225) COMMENT '姓名', sex TINYINT(1) DEFAULT 1 COMMENT '性别 1男 0女', PRIMARY KEY (id) ) ENGINE=INNODB CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
第四章 SQL语句之DML && DQL
有关数据表的DML操作
INSERT 针对于数据的插入
DELETE 针对于数据的删除
UPDATE 针对于数据的修改
4.1 INSERT语句
INSERT INTO 表名 [(列名1,列名2,....)] VALUES (值1,值2,...);
默认情况下,一条插入命令只针对一行进行影响
INSERT INTO 表名 [(columnName,[columnName...])] VALUES (value[,value....]),(value[,value....]),(value[,value....]).....;
一次性插入多条记录
PS 如果我们为每一列都要指定注入的值,那么表名后面就不需要罗列插入的列名了
INSERT INTO 表名 VALUES (值1,值2,值3,....)
CREATE TABLE `grade` (
`GradeID` int(0) NOT NULL AUTO_INCREMENT COMMENT '年级编号',
`GradeName` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '年级名称',
PRIMARY KEY (`GradeID`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
4.2 REPLACE语句
replace语句的语法格式有三种语法格式。
语法格式1:
replace into 表名 [(字段列表)] values (值列表);
语法格式2:
replace [into] 目标表名[(字段列表1) select (字段列表2) from 源表 [where 条件表达式];
语法格式3:
replace [into] 表名 set 字段1=值1, 字段2=值2;
REPLACE与INSERT语句区别:
replace语句的功能与insert语句的功能基本相同,不同之处在于:使用replace语句向表插入新记录时,如果新记录的主键值或者唯一性约束的字段值与已有记录相同,则已有记录先被删除(注意:已有记录删除时也不能违背外键约束条件),然后再插入新记录。
使用replace的最大好处就是可以将delete和insert合二为一(效果相当于更新),形成一个原子操作,这样就无需将delete操作与insert操作置于事务中了
4.3 DELETE语句 || TRUNCATE语句
DELETE (TRUNCATE) FROM 表名 [WHERE 条件];
DELETE:删除数据,保留表结构,必要时可以回滚,但是如果数据量较大,运行速度不及TRUNCATE。
TRUNCATE:删除所有数据,保留表结构,不能够回滚。一次全部删除所有数据,速度相对很快。
DROP:删除数据和表结构,删除速度最快。
4.4 UPDATE数据
UPDATE 表名 SET 列名 = 值 [,列名 = 值,列名 = 值,列名 = 值,...] [WHERE 条件];
4.5 核心资料
1:建库 MySchool_db
CREATE DATABASE Myschool_db;
2:建表(先主后从)
2.1创建年级表
CREATE TABLE grade(
GradeID INT NOT NULL AUTO_INCREMENT COMMENT '年级编号',
GradeName VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '年级名称',
PRIMARY KEY (GradeID)
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci;
2.2创建科目表
DROP TABLE IF EXISTS subject;
CREATE TABLE subject (
SubjectNo int NOT NULL AUTO_INCREMENT COMMENT '课程编号',
SubjectName varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '课程名称',
ClassHour int NULL DEFAULT NULL COMMENT '学时',
GradeID int NULL DEFAULT NULL COMMENT '年级编号',
PRIMARY KEY (SubjectNo)
) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci;
2.3创建学生表
DROP TABLE IF EXISTS student;
CREATE TABLE student (
StudentNo int(0) NOT NULL COMMENT '学号',
LoginPwd varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
StudentName varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '学生姓名',
Sex tinyint(1) NULL DEFAULT NULL COMMENT '性别,取值0或1',
GradeId int(0) NULL DEFAULT NULL COMMENT '年级编号',
Phone varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系电话,允许为空,即可选输入',
Address varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '地址,允许为空,即可选输入',
BornDate datetime(0) NULL DEFAULT NULL COMMENT '出生时间',
Email varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱账号,允许为空,即可选输入',
IdentityCard varchar(18) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '身份证号',
PRIMARY KEY (StudentNo) USING BTREE,
UNIQUE INDEX IdentityCard(IdentityCard) USING BTREE,
INDEX Email(Email) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci;
2.4创建成绩表
CREATE TABLE `result` (
`StudentNo` int(0) NOT NULL COMMENT '学号',
`SubjectNo` int(0) NOT NULL COMMENT '课程编号',
`ExamDate` datetime(0) NOT NULL COMMENT '考试日期',
`StudentResult` int(0) NOT NULL COMMENT '考试成绩',
INDEX `SubjectNo`(`SubjectNo`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>注入年级数据
INSERT INTO `grade` VALUES (1, '大一');
INSERT INTO `grade` VALUES (2, '大二');
INSERT INTO `grade` VALUES (3, '大三');
INSERT INTO `grade` VALUES (4, '大四');
INSERT INTO `grade` VALUES (5, '预科班');
INSERT INTO `grade` VALUES (6, '幼儿园');
INSERT INTO `grade` VALUES (7, '老年大学');
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>注入科目数据
INSERT INTO `subject` VALUES (1, '高等数学-1', 110, 1);
INSERT INTO `subject` VALUES (2, '高等数学-2', 110, 2);
INSERT INTO `subject` VALUES (3, '高等数学-3', 100, 3);
INSERT INTO `subject` VALUES (4, '高等数学-4', 130, 4);
INSERT INTO `subject` VALUES (5, 'C语言-1', 110, 1);
INSERT INTO `subject` VALUES (6, 'C语言-2', 110, 2);
INSERT INTO `subject` VALUES (7, 'C语言-3', 100, 3);
INSERT INTO `subject` VALUES (8, 'C语言-4', 130, 4);
INSERT INTO `subject` VALUES (9, 'JAVA第一学年', 110, 1);
INSERT INTO `subject` VALUES (10, 'JAVA第二学年', 110, 2);
INSERT INTO `subject` VALUES (11, 'JAVA第三学年', 100, 3);
INSERT INTO `subject` VALUES (12, 'JAVA第四学年', 130, 4);
INSERT INTO `subject` VALUES (13, '数据库结构-1', 110, 1);
INSERT INTO `subject` VALUES (14, '数据库结构-2', 110, 2);
INSERT INTO `subject` VALUES (15, '数据库结构-3', 100, 3);
INSERT INTO `subject` VALUES (16, '数据库结构-4', 130, 4);
INSERT INTO `subject` VALUES (17, 'C#基础', 130, 1);
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>注入学生数据
INSERT INTO `student` VALUES (1000, '111111', '郭靖', 1, 1, '13500000001', '北京海淀区中关村大街1号', '1986-12-11 00:00:00', 'test1@openlab.cn', '450323198612111234');
INSERT INTO `student` VALUES (1001, '123456', '李文才', 1, 2, '12345678901', '广东广州天河区', '1981-12-31 00:00:00', 'test1@openlab.cn', '450323198112311234');
INSERT INTO `student` VALUES (1002, '111111', '李斯文', 1, 1, '13500000003', '天津市和平区', '1986-11-30 00:00:00', 'test1@openlab.cn', '450323198611301234');
INSERT INTO `student` VALUES (1003, '123456', '武松', 1, 3, '13500000004', '上海市金桥区', '1986-12-31 00:00:00', 'test1@openlab.cn', '450323198612314234');
INSERT INTO `student` VALUES (1004, '123456', '张三', 1, 4, '13500000005', '北京市通州', '1989-12-31 00:00:00', 'test1@openlab.cn', '450323198612311244');
INSERT INTO `student` VALUES (1005, '123456', '张秋丽 ', 2, 1, '13500000006', '广西桂林市灵川', '1986-12-31 00:00:00', 'test1@openlab.cn', '450323198612311214');
INSERT INTO `student` VALUES (9527, '888999', '赵尧林', 1, 1, '19988887777', '西安市雁塔区新家坡3号楼', '2000-01-01 00:00:00', 'zhaoyaolin@163.com', '610101200002029988');
INSERT INTO `student` VALUES (1007, '111111', '欧阳峻峰', 1, 1, '13500000008', '北京东城区', '1986-12-31 00:00:00', NULL, '450323198612311133');
INSERT INTO `student` VALUES (1008, '111111', '梅超风', 1, 1, '13500000009', '河南洛阳', '1986-12-31 00:00:00', NULL, '450323198612311221');
INSERT INTO `student` VALUES (1028, '111111', '赵敏', 1, 3, '13955556666', '西安市雁塔区', NULL, NULL, NULL);
INSERT INTO `student` VALUES (8080, '123123', '李寻欢', 1, 1, '13677778888', '西安市碑林区', '2005-05-01 00:00:00', 'litian@qq.com', '610101200505019900');
4.6 SELECT 语句(DQL数据查询语言)
基础语法
SELECT {*,列名,函数}
FROM 表名
[WHERE 条件];
说明:
-SELECT检索关键字 *匹配所有列 , 匹配指定列
-FROM 所提供的数据源(表,视图,另一个查询机制反馈的结果)
-WHERE 条件(控制查询的区域)
SELECT *
FROM student; #查询学生表的所有列以及所有行 ====> 学生表的全部信息
SELECT StudentName,Address,Email #查询指定三列的内容所有行 ====> 学生表的姓名 住址 邮箱
FROM student;
SELECT StudentName,Address,Email #查询指定三列的内容指定行 ====> 学生表的姓名 住址 邮箱
FROM student
WHERE sex = 0;
#结论 SELECT 关键字 和 FROM 关键字之间 写的东西 控制的是我们结果的列数
# WHERE 写的东西 控制的是我们结果的行数
#生日在2000-01-01 2010-01-01 的男生 的 姓名
SELECT StudentName
FROM student
WHERE BornDate>'2000-01-01' AND BornDate<'2010-01-01' AND sex = 1;
SELECT 语句中的算数表达式
对数值型数据列、变量、常量可以使用算数操作符创建表达式(+ - * /)
对日期型数据列、变量、常量可以使用部分算数操作符创建表达式(+ -)
运算符不仅可以在列和常量之间进行运算,也可以在多列之间进行运算。
SELECT 100+80;
SELECT '300'+80; #只要其中一个是数值类型,而另一个能够转成数值,则自动转换并计算
SELECT 'ABC'+20; #若转换不成功,则将其认为是数字0对待
SELECT 'Hello'+'World'; #若转换不成功,则将其认为是数字0对待
SELECT NULL+80; #只要有一个为NULL,则结果为NULL
运算符优先级
乘除优先级高于加减
同级运算时运算顺序由左到右
表达式内使用括号,可以改变优先级的运算顺序
SELECT *
FROM subject;
+-----------+-------------------+-----------+---------+
| SubjectNo | SubjectName | ClassHour | GradeID |
+-----------+-------------------+-----------+---------+
| 1 | 高等数学-1 | 110 | 1 |
| 2 | 高等数学-2 | 110 | 2 |
| 3 | 高等数学-3 | 100 | 3 |
| 4 | 高等数学-4 | 130 | 4 |
| 5 | C语言-1 | 110 | 1 |
| 6 | C语言-2 | 110 | 2 |
| 7 | C语言-3 | 100 | 3 |
| 8 | C语言-4 | 130 | 4 |
| 9 | JAVA第一学年 | 110 | 1 |
| 10 | JAVA第二学年 | 110 | 2 |
| 11 | JAVA第三学年 | 100 | 3 |
| 12 | JAVA第四学年 | 130 | 4 |
| 13 | 数据库结构-1 | 110 | 1 |
| 14 | 数据库结构-2 | 110 | 2 |
| 15 | 数据库结构-3 | 100 | 3 |
| 16 | 数据库结构-4 | 130 | 4 |
| 17 | C#基础 | 130 | 1 |
+-----------+-------------------+-----------+---------+
SELECT SubjectName,ClassHour,ClassHour*10+10
FROM subject;
SELECT SubjectName,ClassHour,ClassHour*(10+10)
FROM subject;
NULL值的使用
String str = null;
String str = "";
null指的是 不可用、未分配的值
null不等于零或空格
任意数据类型都支持null这种表达形式
包括null的任何算数表达式结果都等于空
字符串和null进行连接运算,结果也是空
补充点
<==> 安全等于 等价于 = 和 IS 两者的结合
示例1:查询学号为1001的学生信息
SELECT *
FROM student
WHERE StudentNo <==> 1001; # WHERE StudentNo = 1001;
示例2:查询邮箱为空的学生的信息
SELECT *
FROM student
WHERE Email <==> NULL; # WHERE Email IS NULL;
祛除重复的记录
#我想查看学生表的性别
#缺省情况下查询显示所有行,包括重复行
SELECT sex "性别"
FROM student;
#可以使用关键字DISTINCT清除查询记录中的重复数据
SELECT DISTINCT sex "性别"
FROM student;
WHERE 限制所选择的横向区域
WHERE中的字符串或日期格式的内容
需要使用单引号进行专门的标识 如 StudentName = '张三' 而不能 直接 StudentName = 张三
字符串内的数据 对大小写是敏感的 如记录中有 Louis77@163.com 我们在检索时就不能 louis77@163.com
日期值对格式是敏感的 如记录中有 2000-01-01 00:00:00 我们在检索时就不能 2000年01月01日
#示例1:查询姓名是郭靖的学生信息
SELECT *
FROM student
WHERE StudentName = '郭靖';
#示例2:查询生日是1986-12-31的学生信息
SELECT *
FROM student
WHERE BornDate = '1986-12-31';
#示例3:查询学号是1000的学生信息
SELECT *
FROM student
WHERE StudentNo = 1000;
#WHERE中的比较运算符 < > <= >= != =
#示例4:查询生日在2000-01-01之后的学生信息
SELECT *
FROM student
WHERE BornDate > '2000-01-01';
#WHERE中逻辑运算符 AND OR NOT
#AND需要所有条件都满足
#示例5:查询班级编号是1,并且生日在1980-01-01之后,并且性别是1的学生信息
SELECT *
FROM student
WHERE GradeId = 1 AND BornDate > '1980-01-01' AND sex = 1;
#OR只要满足多条件之一即可
#示例6:查询班级编号是1,或者生日在1980-01-01之后,或者性别是1的学生信息
SELECT *
FROM student
WHERE GradeId = 1 OR BornDate > '1980-01-01' OR sex = 1;
#NOT表示取反
#示例7:查询邮箱不为空的学生的姓名,邮箱地址
SELECT StudentName "姓名",Email "邮箱地址"
FROM student
WHERE Email IS NOT NULL;
#示例8:查询生日在2000-2010之间的学生姓名
SELECT StudentName "姓名"
FROM student
WHERE BornDate >= '2000-01-01' AND BornDate <= '2010-01-01';
#示例9:使用BETWEEN关键字实现范围查询
SELECT StudentName "姓名"
FROM student
WHERE BornDate BETWEEN '2000-01-01' AND '2010-01-01';
#示例10:查询 班级是1或2或3班的学生姓名
SELECT StudentName "姓名"
FROM student
WHERE GradeId = 1 OR GradeId = 3 OR GradeId = 2;
#示例11:使用IN关键字进行匹配
SELECT StudentName "姓名"
FROM student
WHERE GradeId IN (1,2,3);
定义字段的别名
SELECT StudentName,Address,Email
FROM student;
+--------------+------------------------------------+--------------------+
| StudentName | Address | Email |
+--------------+------------------------------------+--------------------+
| 郭靖 | 北京海淀区中关村大街1号 | test1@bdqn.cn |
| 李文才 | 广东广州天河区 | test1@bdqn.cn |
| 李斯文 | 天津市和平区 | test1@bdqn.cn |
| 武松 | 上海市金桥区 | test1@bdqn.cn |
| 张三 | 北京市通州 | test1@bdqn.cn |
| 张秋丽 | 广西桂林市灵川 | test1@bdqn.cn |
| 欧阳峻峰 | 北京东城区 | NULL |
| 梅超风 | 河南洛阳 | NULL |
| 赵敏 | 西安市雁塔区 | NULL |
| 李寻欢 | 西安市碑林区 | litian@qq.com |
| 赵尧林 | 西安市雁塔区新家坡3号楼 | zhaoyaolin@163.com |
+--------------+------------------------------------+--------------------+
#查询语句获取到的结果 是以伪表形式体现
SELECT StudentName AS '学生姓名',Address AS '家庭住址',Email AS '电子邮箱'
FROM student;
SELECT SubjectName "科目名",ClassHour "学习时长",ClassHour*(10+10) "计算后的学习时长"
FROM subject;
第五章 MySQL的备份及恢复
5.1 MySQL日志管理
在数据库保存数据时,有时候不可避免会出现数据丢失或者被破坏,这样情况下,我们必须保证数据的安全性和完整性,就需要使用日志来查看或者恢复数据了
数据库中数据丢失或被破坏可能原因:
1、误删除数据库
2、数据库工作时、意外程序终止、程序崩溃
3、病毒的入侵
4、文件系统损坏后,系统进行自检操作时,误删除了核心数据
5、升级数据库时、命令不严格
6、设备故障,硬件损坏
7、自然灾害,被盗
5.1.1 MySQL日志类型
日志类型 | 记录文件中的信息类型 |
---|---|
错误日志 | 记录启动、运行或停止时出现问题 |
查询日志 | 记录建立的客户端连接和执行的语句 |
二进制日志 | 记录所有更改数据的语句。主要用于复制或即时点恢复 |
慢日志 | 记录所有执行时间超过最大查询时间 long_query_time 的查询操作或不使用索引的查询 |
事务日志 | 记录InnoDB等支持事务管理的存储引擎执行事务时所产生的日志 |
默认情况下,所有日志都创建于mysqld数据目录内,通过刷新日志,你可以强制 mysqld来关闭和重新打开||切换日志文件。
mysql > FLUSH LOGS 或 mysqladmin flush-logs
5.1.2 错误日志
错误日志中主要记录的几种日志:
1、服务器启动和关闭过程中的信息
2、务器运行过程中的错误信息
3、事件调度器运行一个时间是产生的信息
4、在从服务上启动进程时所产生的信息
错误日志的定义:
可以用--log-error[=file_name]选项来指定mysqld保存错误日志文件的位置。
如果没有给定file_name值,mysqld使用错误日志名host_name.err 并在数据目录中写入日志文件。
如果执行刷新操作,错误日志用-old重新命名后缀并且mysqld创建一个新的空日志文件。
#错误日志 mysql> SHOW GLOBAL VARIABLES LIKE '%log_error%'; #警告日志 mysql> SHOW GLOBAL VARIABLES LIKE '%log_warning%';
5.1.3 通用查询日志
启动开关 general_log = {ON||OFF}
日志文件变量 general_log_file [=/PATH/TO/file]
全局日志开关 log = {ON||OFF}
记录类型 log_output = {TABLE||FILE||NONE}
如果需要启用通用查询日志 至少要配置 general_log = NO ,log_output = {TABLE||FILE}
如果general_log_file 没有额外指定 默认名为 host_name.log
mysql> SHOW GLOBAL VARIABLES LIKE '%general_log%'; mysql> SHOW GLOBAL VARIABLES LIKE '%log_output%';
5.1.4 慢查询日志
Mysql 如果启用了 slow_query_log = ON 选项。就会记录执行时间超过long_query_time的查询。
日志记录文件为slow_query_log_file[=file_name] 若没有给定file_name, 默认为主机名,后缀为-slow.log。
与慢查询相关的变量设置:
# 系统默认关闭慢查询日志开关 查看状态 MYSQL> SHOW GLOBAL VARIABLES LIKE '%slow_query_log%'; #开启方式 SET GLOBAL slow_query_log=ON; #查看默认的查询时效 MYSQL> SHOW GLOBAL VARIABLES LIKE 'long_query_time';
5.1.5 二进制日志
开启日志
二进制日志启动开关:log-bin [= file_name]。
5.6版本
前:一定要手动指定
后:默认file_name为$datadir/mysqld-binlog
查看二进制日志的工具为 mysqlbinlog
二进制日志包含了所有更新了数据或者已经潜在更新了数据。语言语句以事件形式保存,描述了数据的更改。
二进制日志还包含关于每个更新数据库的语句的执行时间信息。
作用:当数据库存在故障时,恢复能尽最大可能进行即时点恢复,因为二进制日志内包含了备份后进行的所有更新,所以二进制日志还用于在主复制服务器上记录所有将发送给从服务器的语句。
二进制日志是记录执行的语句还是 执行后的数据 ???
情况1:假如一个表有10万行数据,而现在要执行一个如下语句将amount字段的值全部在原来的基础上增加1000
UPDATE sales.january SET amount=amount+1000 ;
如果影响的行数过于庞大,日志内记录的是执行的语句
情况2:如果像某一个指定的行内字段插入数据
UPDATE student SET Email = "XXX" WHERE StudentNo = ???;
此时就不能记录语句了,因为不同时间执行的结果是不一样的。这是应该记录这一行的值,这种就是基于行(row)的二进制日志
情况3:如果出现触发器 存储函数 这种方式进行数据的更新的话,可能会结合两种方式来进行记录,这种叫做 混合方式的二进制日志
日志滚动
在my.cnf中设定max_binlog_size = 200M,表示限制二进制日志最大尺寸为200M,超过200M后进行滚动。
MySQL的滚动方式与其他日志不太一样,滚动时会创建一个新的编号大1的日志用于记录最新的日志,而 原日志名字不会被改变。每次重启MySQL服务,日志都会自动滚动一次。
#日志查看 查看有哪些二进制日志文件:mysql> SHOW BINARY LOGS; 查看当前正在使用的是哪一个二进制日志文件:mysql> SHOW MASTER STATUS;
5.2 MySQL备份
5.2.1备份类型
根据服务器的状态,备份分为三种类型:热备份、温备份、冷备份。
热备份:读、写不受影响;
温备份:仅可以执行读操作;
冷备份:读写均终止,离线备份;
从对象的角度分析,分为物理备份以及逻辑备份
物理备份:复制数据文件
逻辑备份:将数据导出至目标 XXX.sql文件中
从数据收集上来分,分为完全备份、增量备份、差异备份
完全备份:备份全部的数据
增量备份:仅备份上次完全备份或增量备份后所变化的数据
差异备份:仅备份上次完全备份后变化的数据
逻辑备份的优缺点
优点:
在备份速度上两种备份要取决于当前的存储引擎
物理备份的还原速度非常快,但是物理备份的最小单元只能做到表
逻辑备份保存的结构通常都是ASCII形式,所以我们只能通过.sql方式进行保存
逻辑备份有非常强的兼容性,而物理备份对版本要求非常高
逻辑备份对保持数据的安全性有保障
缺点:
逻辑备份会对DBMS产生额外的压力,物理备份则无明显压力
逻辑备份的结果可能比信息本身还要大。可以通过压缩来缓解这一现象。
针对于高精度内容,逻辑备份可能会倒置浮点精度丢失。
5.2.2 备份内容
数据文件 数据结构 日志(二进制日志,事务日志) 存储过程,存储函数,触发器 个人配置信息 脚本信息
5.2.3 常见的备份工具
MySQL自带的工具
基于DBMS=====> mysqldump
mysqldump 是mysql数据库管理系统,自带的逻辑备份工具。支持所有的主流引擎,MyISAM引擎是温备,InnoDB引擎是热备。备份速度中等,还原速度较慢。因此在实现还原时,我们会采用其他的方式进行操作。
#备份所有数据库: mysqldump -uroot -p --all-databases > /usr/local/databases.sql #备份指定的数据库(数据表) mysqldump -uroot -p MySchool_db student grade > /usr/local/MySchool_db.sql; ------------------------------------------------------------------------------------------- #还原方式1 use MyScl_db; source/usr/local/MySchool_db.sql; #还原方式2 mysql -uroot -p MyScl_db < /usr/local/MySchool_db.sql --------------------------------------------------------------------------------------------
其他工具
ibbackup 商业工具 MyISAM是温备份,InnoDB是热备份 ,备份和还原速度都很快,这个软件它的每服务器授权版本是5000美元。
xtrabackup 开源工具 MyISAM是温备份,InnoDB是热备份 ,是ibbackup商业工具的替代工具。
mysqlbackup ORACLE公司也提供了针对企业的备份软件MySQL Enterprise Backup简称:mysqlbackup。
MySQL企业备份工具执行在线“热备“,无阻塞的MySQL数据库备份。全备份可以在所有InnoDB数据库上 执行,而无需中断MySQL查询或更新。此外,支持增量备份,只备份自上次备份后有变化的数据。另外部分备 份,支持特定的表或表空间按需要进行备份。
#备份 选择需要备份的数据库,右键-》备份/导出-》以SQL转储文件备份数据库 选择需要恢复的数据库,右键-》导入-》从sql转储文件导入数据库 PS 不要混用,可能会出现冲突,注意甄别核心命令
第六章 视图与索引
6.1 视图
6.1.1 什么是视图
视图通过 定制的方式显示来自一个表或多个表的数据。
视图的本质 是数据库对象,如果成功的创建了视图,用户可以像操作普通表一样查询甚至修改视图内的数据。
视图的本身是没有任何的数据的 ,它只是对表的一个查询结果进行了实体化的反馈。
有关于视图所有的定义,保存在数据字典内,创建视图所基于的表称为"基表"。
6.1.2 为什么要使用视图
例如经常要对 student和grade表进行连接查询,每次都要做冗余的连接,才能完成后续的检索或分析过于麻烦。同时对于一些私密的信息,并不想让其他的操作人访问,我们就可以实现准备好一个定制化的视图供他去使用。
6.1.3 视图的作用和特点
作用
1、保存查询数据
2、控制安全
优点
1、提供了灵活一致级别的安全性
2、隐藏了数据原有的复杂性
3、简化了用户对于SQL指令的编辑
4、通过重命名列,从另一角度提供数据
6.1.4 视图的创建
#语法: CREATE [OR REPLACE] VIEW 视图名 [别名1,别名2,.....] AS 必要的查询语句 [额外的声明 ===> WITH READ ONLY]; #如:创建视图,Student_V_1 包含了一号班级编号的所有学生的学号 姓名 班级名称 生日 住址 CREATE VIEW Student_V_1 AS SELECT student.StudentNo,student.StudentName,grade.GradeName,student.BornDate,student.Address FROM student INNER JOIN grade ON student.GradeID = grade.GradeID WHERE student.GradeID = 1; CREATE VIEW Student_V_2 (学号,姓名,班级名,生日,邮箱) AS SELECT student.StudentNo,student.StudentName,grade.GradeName,student.BornDate,student.Address FROM student INNER JOIN grade ON student.GradeID = grade.GradeID WHERE student.GradeID = 1; #查询当前数据库内所有的视图 SHOW FULL TABLES WHERE Table_type = 'VIEW';
6.1.5 视图的使用规则
1、视图必须有唯一命名
2、mysql中对于视图的数量没有限制
3、创建视图的权限,必须要进行授权
4、视图支持嵌套,也就是说可以利用其他视图检索出来的数据创建新视图
5、视图内支持分组查和排序查,但是会覆盖掉原有的排序或分组机制
6、视图不能创建索引,也不能关联触发器
7、视图和表可以出现在同一查询语境内
6.1.6 视图的修改
#如替换原有视图信息 CREATE OR REPLACE Student_V_1 ....................... #比如XXX人创建视图时Email赋值赋的是生日 通过ALTER关键字可以实现视图中字段值的重新赋予 ALTER VIEW Student_V_1 (Email) AS SELECT Email FROM student; #注意一下 ALTER VIEW Student_V_1 (Email) AS SELECT Email FROM student; ALTER VIEW Student_V_2 (邮箱) AS SELECT student.Email FROM student INNER JOIN grade ON student.GradeID = grade.GradeID WHERE student.GradeID = 1;
6.1.7 视图的删除
DROP VIEW 视图名;
6.2 索引
索引是一种很特殊的数据库结构,可以用来快速查询数据库表中的特定记录。它也是提高数据库性能的重要手段。从理论上分析,在MySql中,所有的数据类型,都可以被索引。常见的索引:普通索引、惟一性索引、全文索引、单列索引、多列索引和空间索引等。
6.2.1 什么是索引
模式(schema)中的一个数据库对象 在数据库中用来加速对表的查询 通过使用快速路径访问方法快速定位数据,减少了磁盘的I/O 与表独立存放,但不能独立存在,必须属于某个表 由数据库自动维护,表被删除时,该表上的索引自动被删除。 索引的作用类似于书的目录,几乎没有一本书没有目录,因此几乎没有一张表没有索引。
索引的原理
将无序的数据变成有序的查询
1:把创建了索引的列的内容进行排序
2:对排序的结果生成相应的倒排表
3:在倒排表的内容上拼上数据地址链
4:在进行查询的时候,先拿到倒排表内容,再取出数据地址链,从而得到具体的数据
6.2.2 索引的优缺点
索引的优点是可以提高检索数据的速度,这是创建索引的最主要的原因。对于有依赖关系的子表和父表之间的 联合查询时,可以提高查询速度。使用分组和排序子句进行数据查询时,同样可以显著节省查询中分组和排序的时间。
索引的缺点是创建和维护索引需要耗费时间;耗费时间的数量随着数据量的增加而增加;索引需要占用物理空 间,每一个索引要占一定的物理空间;增加、删除和修改数据时,要动态的维护索引,造成数据的维护速度降低了。
6.2.3 索引分类
索引分为聚簇索引和非聚簇索引两种,聚簇索引是按照数据存放的物理位置为顺序的,而非聚簇索引就不一样了。
聚簇索引能提高多行检索的速度,而非聚簇索引对于单行的检索很快
常见的索引:普通索引、惟一性索引、全文索引、单列索引、多列索引和空间索引等。
6.2.4 索引设计原则
为了使索引的使用效率更高,在创建索引的时候必须考虑在哪些字段上创建索引和创建什么类型的索引。
1、尽量去选择唯一性索引。
2、为经常需要去排序、分组、联合操作的字段建立索引。
3、为经常作为查询条件的字段建立索引。
4、索引并不是越多越好,严格限制索引的数目。
5、尽量使用数据量小的索引。
6、及时的去删除一些使用很少或不再使用的索引。
6.2.5 创建索引
创建索引是指在某个表的一列或多列上建立索引的行为。有三种方式创建索引:创建表的时候(声明字段)时创建索引,在已经存在的表上创建索引,在使用ALTER TABLE语句来创建索引。
创建表的时候可以直接创建索引,这种方式是最为简单和方便的,语法如下: CREATE TABLE 表名( 字段名 字段类型 [约束条件] 字段名 字段类型 [约束条件] 字段名 字段类型 [约束条件] [UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY [别名](属性名1 [(长度)] [ASC | DESC]) ); #示例1:创建表的时候创建索引 CREATE TABLE index1( id INT, name VARCHAR(20), Sex BOOLEAN, INDEX(id) ); #修改表结构的方式添加索引 ALTER TABLE 表名 ADD INDEX 索引名(字段名); #查询某表内索引的使用情况 SHOW INDEX FROM 表名; #删除索引 DROP INDEX 索引名 ON 表名; #示例2:创建唯一性索引 CREATE TABLE index2( id INT unique, #通过申明约束去创建===>自动来的 name VARCHAR(20), Unique INDEX index2_id(id asc) #通过专门去做索引创建===> ); ALTER TABLE index2 ADD INDEX index2_name(name); #示例3:创建单列索引 CREATE TABLE index3( id int, Subject varchar(30), INDEX index3_st(subject(10)) ); #示例4:创建多列索引 CREATE TABLE index4( id int, name VARCHAR(20), sex CHAR(4), INDEX index4_ns(name,sex) ); 使用多列索引时一定要特别注意,只有使用了索引中的第一个字段时才会触发索引。 如果没有使用索引中的第一个字段,那么这个多列索引就不会起作用。 也就是说多个单列索引与单个多列索引的查询效果不同,因为执行查询时, MySQL只能使用一个索引,会从多个索引中选择一个限制最为严格的索引。 #还可以通过 CREATE INDEX 去创建索引 首先要保证已经存在表,才能够使用这个命令去创建索引. 在已经存在的表上,可以直接为表上的一个或几个字段创建索引。 CREATE [ UNIQUE | FULLTEXT | SPATIAL ] INDEX 索引名 ON 表名 (属性名 [ (长度) ] [ ASC | DESC] ); CREATE TABLE index5( id int, name VARCHAR(20), sex CHAR(4) ); #为 name 字段创建普通索引 CREATE [ UNIQUE | FULLTEXT ] INDEX index5_name ON index5 (name(10)); #还可以通过ALTER TABLE语句创建索引 首先要保证已经存在表,才能够使用这个命令去创建索引. ALTER TABLE 表名 ADD [ UNIQUE | FULLTEXT | SPATIAL ] INDEX 索引名 (属性名 [ (长度) ] [ ASC | DESC] ); CREATE TABLE index6( id int, name VARCHAR(20), sex CHAR(4) ); ALTER TABLE index6 ADD INDEX index6_name (name(10));
6.2.6 删除索引
删除索引是指将表中已经存在的索引删除掉。一些不再使用的索引会降低表的更新速度,影响数据库的性能。 DROP INDEX 索引名 ON 表名;
6.2.7 索引的使用场景和索引的优化
1) 快速查找符合where条件的记录。 2) 快速确定候选集。若where条件使用了多个索引字段,则MySQL会优先使用能使候选记录集规模最小的那 个索引,以便尽快淘汰不符合条件的记录。 3) 如果表中存在几个字段构成的联合索引,则查找记录时,这个联合索引的最左前缀匹配字段也会被自动作 为索引来加速查找。 例如:若为某表创建了3个字段(c1, c2, c3)构成的联合索引,则(c1), (c1, c2), (c1, c2, c3)均 会作为索引,(c2, c3)就不会被作为索引,而(c1, c3)其实只利用到c1索引。 4) 多表做join操作时会使用索引(如果参与join的字段在这些表中均建立了索引的话)。 5) 若某字段已建立索引,求该字段的min()或max()时,MySQL会使用索引。 6) 对建立了索引的字段做sort或group操作时,MySQL会使用索引。
索引的优化
动作描述 | 使用聚簇索引 | 使用非聚簇索引 |
---|---|---|
列经常被分组查询 | 1 | 1 |
返回某范围内的数据 | 1 | 0 |
一个或极少的范围值 | 0 | 0 |
小数目的不同值 | 1 | 0 |
大数目的不同值 | 0 | 1 |
频繁更换的列 | 0 | 0 |
外键列 | 1 | 1 |
主键列 | 1 | 1 |
频繁修改的列 | 0 | 0.5 |
6.2.8 聚餐索引和非聚簇索引
非聚簇索引
索引节点的叶子页面就好比一片叶子。叶子头便是索引键值
会利用索引,先在索引树中快速检索到 id,但是要想取到id对应行数据,必须找到该行数据在硬盘中的存储位置。
因此MYISAM引擎的索引,叶子页面上不仅存储了主键id 还存储着 数据存储的地址信息。
像这样的索引就称为非聚簇索引。它的二级索引与主键索引类似。
聚簇索引
对于非聚簇索引来说,每次通过索引检索到所需行号后,还需要通过叶子上的磁盘地址去磁盘内取数据(回行)消耗时间。为了优化这部分回行取数据时间,InnoDB 引擎采用了聚簇索引。
聚簇索引,即将数据存入索引叶子页面上。对于 InnoDB 引擎来说,叶子页面不再存该行对应的地址,而是直接存储数据。
这样就可以避免回行操作所带来的时间消耗。
关于查询时间,一般认为 MyISAM 牺牲了功能换取了性能,查询更快。但事实并不一定如此。多数情况下,MyISAM 确实比 InnoDB 查的快 。但是查询时间受多方面因素影响。InnoDB 查询变慢得原因是因为支持事务、回滚等等,使得 InnoDB的叶子页面实际上还包含有事务id(换句话说就是版本号) 以及回滚指针。
在二级索引方面 InnoDB与MyISAM 有很大的区别
InnoDB默认对主键建立聚簇索引。如果你不指定主键,InnoDB会用一个具有唯一且非空值的索引来代替。如果不存在这样的索引,InnoDB会定义一个隐藏的主键,然后对其建立聚簇索引。
第七章 SQL编程
1.触发器
1.1触发器简介
触发器是一种比较特殊的存储过程,它的执行不是由程序调用,也不是手工调用,而是通过事件来进行触发。
比如说 对一张表 进行(增,删,改),去激活它的执行。
触发器经常应用在加强数据完整性,和业务规则中,如:当一个学生表中添加了一个学生信息时,那么对应的学生数目肯定会有所改变。像这样的情况,我们就可以针对学生表创建一个触发器:以确保每次增加一个学生记录时,就执行一次关于学生总数的计算操作,从而确保学生总数与记录数的一致性。
1.2 触发器的创建
#语法要求 CREATE TRIGGER 触发器名称 BEFORE|AFTER 触发事件 ON 表名 FOR EACH ROW BEGIN 触发器程序体; END #说明 <触发器名称> 参考索引命名||表命名 BEFORE|AFTER 触发器时机 INSERT DELETE UPDATE 触发的事件 ON 表名 在哪张表上建立触发器 FOR EACH ROW 触发器执行间隔策略 ===> 字句通知触发器,每隔一行执行一次动作,并不是对整个表执行。 触发器程序体 要出发的SQL语句
1.3 示例
#当前有两张表 student student_count #每当学生表中有记录增加(减少)时那么学生行数的这个表,需要进行最新的行数统计 1.创建表 CREATE TABLE student( id int auto_increment primary key not null, name varchar(40) ); CREATE TABLE student_count( totle int ); #添加一条学生信息 INSERT INTO student (name) VALUES('jack_1'); INSERT INTO student_count VALUES(1); #后面student表的添加语句与前面的一致 #而student_count语句全都会变为UPDATE格式 #故创建触发器: CREATE TRIGGER student_insert_trigger AFTER INSERT ON student FOR EACH ROW BEGIN UPDATE student_count SET totle = totle+1; END; #查看触发器是否已存在 SHOW TRIGGERS; #我们插入若干条数据进行测试 INSERT INTO student (name) VALUES('jack_2'),('jack_3'),('jack_4'),('jack_5'),('jack_6'),('jack_7'),('jack_8'),('jack_9'),('jack_10'); #套用语法完成删除的触发器 CREATE TRIGGER student_delete_trigger AFTER DELETE ON student FOR EACH ROW BEGIN UPDATE student_count SET totle = totle-1; END; #示例2:职员表 (工号,姓名,性别,年龄) <===> 工资表 (工资编号,姓名,工资5000) 对职工进行添加时 工资表中也要体现当前职工的信息 对职工进行修改时 工资表中也要一并修改当前职工的信息 对职工进行解聘时 工资表中也要一并删除当前员工的工资信息 #创建职工表 CREATE TABLE tab1( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20), sex ENUM('m','f'), age INT ); #创建工资表 CREATE TABLE tab2( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20), salary DOUBLE(10,2) ); #创建触发器1 INSERT 对职工进行添加时 工资表中也要体现当前职工的信息 CREATE TRIGGER tab1_insert_trigger AFTER INSERT ON tab1 FOR EACH ROW BEGIN INSERT INTO tab2 VALUES (NULL,new.name,5000); END; 测试用户新增 INSERT INTO tab1 VALUES (1,'AA','f',18); 新增完成后我们检查tab2会发现有变化 #创建触发器2 UPDATE 对职工进行修改时 工资表中也要刷新当前职工的信息 CREATE TRIGGER tab1_update_trigger AFTER UPDATE ON tab1 FOR EACH ROW BEGIN UPDATE tab2 SET name = new.name WHERE name = old.name; END; 测试用户修改 UPDATE tab1 SET name = 'FF' WHERE name = 'BB'; 修改完成后我们检查tab2会发现有变化 #创建触发器3 DELETE 对职工进行删除时 工资表中也要刷新当前职工信息 CREATE TRIGGER tab1_delete_trigger AFTER DELETE ON tab1 FOR EACH ROW BEGIN DELETE FROM tab2 WHERE name = old.name; END;
2.存储过程
2.1 什么是存储过程(函数)
存储过程指的是 事先经过了编译并以对象形式存储在数据库中的一段sql语句的集合。调用存储过程可以简化应用开发人员的很多工作,减少了数据在数据库和应用服务器之间的传输,对于提高数据的处理能力具有很强的好处。
存储过程和存储函数的区别:
1、存储过程可以不设返回值,而存储函数必须要设置返回值
2、存储过程的参数 IN OUT INOUT 类型,而存储函数的参数只能是IN
2.2 优势
存储过程旨在创建时编译一次,而常规的SQL命令每执行一次就会编译一次,所以它能够提高执行效率
简化复杂操作,支持封装
复用性极强
安全性高,可以指定其使用权
2.3 应用场景
在并发量较小的情况下,很少使用。在并发量高的情况下,多采用存储过程或存储函数。
2.4 存储过程的创建与使用
CREATE PROCEDURE 函数名(形式参数列表) BEGIN 函数体 END; 参数列表类型 [IN OUT INOUT] 参数名 类型 IN 输入参数 OUT 输出参数 INOUT 该参数在调用方法是充当了实参变量,在方法调用完毕返回结果时又充当了接受返回值的变量 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> CALL函数名(实际参数列表)
各参数类型所实现的存储过程
======================无参数无返回的存储过程======================== #查询当前学生人数 CREATE PROCEDURE p1() BEGIN SELECT COUNT(*) FROM student; END; ======================有参数无返回的存储过程======================== #创建一张测试表 CREATE TABLE t1( id int, name varchar(50) ); CREATE PROCEDURE autoinsert(IN num INT) BEGIN DECLARE i INT DEFAULT 1; WHILE(i<=num)DO INSERT INTO t1 VALUES(i,md5(i)); SET i = i+1; END WHILE; END; ======================无参数有返回的存储过程======================== #查询当前学生人数 CREATE PROCEDURE p2(OUT num INT) BEGIN SELECT COUNT(*) INTO num FROM student; END; ======================有参数有返回的存储过程======================== #统计指定班级编号的学生人数 CREATE PROCEDURE p3(IN num1 INT,OUT num2 INT) BEGIN SELECT COUNT(*) INTO num2 FROM student WHERE student.GradeID = num1; END; ================================INOUT================================= CREATE PROCEDURE p4(INOUT num INT) BEGIN IF(num IS NOT NULL) then SET num = num+1; ELSE SELECT 100 INTO NUM; END IF; END; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> CREATE PROCEDURE p5(INOUT num INT) BEGIN SELECT COUNT(*) INTO num FROM student WHERE student.GradeID = num; END;
3.存储函数
3.1 概念
MySQL存储函数(自定义函数),函数一般用于计算和返回一个值,可以将经常需要使用的计算或功能写成一个函数。函数和存储过程类似。
存储过程和存储函数的区别:
1、存储过程可以不设返回值,而存储函数必须要设置返回值
2、存储过程的参数 IN OUT INOUT 类型,而存储函数的参数只能是IN
3.2 创建和使用
在MySql中创建存储函数使用的关键字 是 CREATE FUNCTION 其基本语法如下:
CREATE FUNCTION 函数名 ([参数名 参数类型,参数名 参数类型....]) RETURNS type [characteristic ...] BEGIN routine_body END; 参数说明: RETURNS type ====> 返回值的类型 characteristic ===> 指定存储函数的特性 routine_body ===> SQL代码内容
调用存储函数
在MySQL中,存储函数的使用方法与MySQL内部函数的使用方法基本相同。用户自定义的存储函数与MySQL内部函数性质相同。区别在于,存储函数是用户自定义的。而内部函数由MySQL自带。其语法结构如下:
SELECT NOW(); SELECT 函数名(实际参数列表)
3.3 示例演示
注意事项:MySQL开启bin-log后,调用存储过程或者函数以及触发器时,会出现错误号为1418的错误 如何解决此问题:信任子程序的创建者,禁止创建、修改子程序时对SUPER权限的要求: 在客户端上执行 SET GLOBAL log_bin_trust_function_creators = 1; #1 =============无参数有返回值============== #统计student表中行数 CREATE FUNCTION myf1() RETURNS INT BEGIN DECLARE num INT DEFAULT 0; SELECT COUNT(*) INTO num FROM student; RETURN num; END; #2 =============有参数有返回值============== #根据学生姓名查询学生学号 CREATE FUNCTION myf2(stuName VARCHAR(20)) RETURNS INT BEGIN DECLARE num INT; SELECT id INTO num FROM student WHERE name = stuName; RETURN num; END; #调用 使用 SELECT命令
3.4 删除
DROP FUNCTION myf2;
4.游标
游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。(遍历)
-
使用游标(cursor)的一个主要的原因就是把集合操作转换成单个记录处理方式。
-
游标充当指针的作用。
-
尽管游标能遍历结果中的所有行,但他一次只指向一行。
-
用SQL语言从数据库中检索数据后,结果放在内存的一块区域中,且结果往往是一个含有多个记录的集合。
-
游标机制允许用户逐行地访问这些记录,按照用户自己的意愿来显示和处理这些记录。
优点
-
允许程序对由查询语句select返回的行集合中的每一行执行相同或不同的操作,而不是对整个行集合执行同一个操作。
-
提供对基于游标位置的表中的行进行删除和更新的能力。
-
游标实际上作为面向集合的数据库管理系统(RDBMS)和面向行的程序设计之间的桥梁,使这两种处理方式通过游标沟通起来。
原理
游标就是把数据按照指定要求提取出相应的数据集,然后逐条进行数据处理。
4.1 如何声明游标
DECLARE cursor_name CURSOR FOR select_statement (table)
4.2 打开游标
声明游标后,想从游标中提取数据,必须要打开游标。OPEN
OPEN cursor_name
注意,当我们执行了打开游标操作后,游标并不是指向第一条记录,而是指向第一条记录的前边。
在程序内,一个游标可以打开多次,用户打开游标后,其他用户或程序可能正在更新数据,所以有时候可能导致用户每次打开游标时,显示的结果不同。
4.3 使用游标
当用户顺利打开游标后,可以使用 FETCH...INTO 语句进行数据的读取
# 这条语句用户指定的打开游标并读取下一行,且前进游标指针。 FETCH cursor_name INTO value1[,value2.....]
4.4 关闭
游标使用完毕后,要及时关闭,在MySQL中,使用CLOSE关键字关闭游标,其语法和格式:
CLOSE cursor_name;
CLOSE 用于释放游标所有的内部资源和内存,因此每个游标再不需要的时候,都需要及时关闭。
关闭的游标 如果没有重新打开,则不能二次使用。但是已经声明过的游标不需要再次声明了,用OPEN语句打开它就可以。
如果忘记关闭,MySql将会在到达END语句时自动关闭。游标关闭后,就不能使用FETCH去进行游标的遍历了。
4.5 游标的应用
示例说明:编写两个表 sys_user和user表,编写其存储过程。当两个表id值一样的时候,将user表内的name字段值同步成 sys_user表的name字段值。
#1创建sys_user表并注入一些数据 CREATE TABLE sys_user( id INT(11) NOT NULL AUTO_INCREMENT, username VARCHAR(200) NOT NULL, PRIMARY KEY(id) )ENGINE=InnoDB AUTO_INCREMENT = 4 DEFAULT CHARSET = utf8; INSERT INTO sys_user (username) VALUES ('AA'),('BB'),('CC'),('DD'),('EE'),('FF'),('GG'); CREATE TABLE user( id INT(11) DEFAULT NULL, name VARCHAR(200) DEFAULT NULL )ENGINE=InnoDB DEFAULT CHARSET = utf8; INSERT INTO user VALUES (1,'OO'),(2,'PP'),(3,'QQ'),(4,'RR'),(5,'SS'),(6,'TT'),(7,'UU');
创建存储过程 user_test,并创建游标 cur_test
CREATE PROCEDURE user_test() BEGIN -- 定义变量 DECLARE sys_user_id BIGINT; DECLARE sys_user_name VARCHAR(11); DECLARE done INT; -- 创建游标,并存储数据 DECLARE cur_test CURSOR FOR SELECT id AS user_id,user_name AS sys_user_name FROM `sys_user`; -- 游标中的内容执行完后将 done 设置为 1 DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1; -- 打开游标 OPEN cur_test; -- 执行循环 posLoop:LOOP -- 判断是否结束循环 IF done=1 THEN LEAVE posLoop; END IF; -- 取游标中的值 FETCH cur_test INTO sys_user_id,sys_user_name; -- 执行更新操作 UPDATE `user` SET NAME=sys_user_name WHERE id=sys_user_id; END LOOP posLoop; -- 释放游标 CLOSE cur_test; END
5.SQL触发器练习
创建职工表以及职工工资表
职工表字段:工号,姓名,性别,年龄
工资表字段:编号自增,职工工号,基础工资10000
通过触发器实现:
对职工进行添加时 工资表中也要体现当前职工的信息
对职工进行修改时 工资表中也要一并修改当前职工的信息
对职工进行解聘时 工资表中也要一并删除当前员工的工资信息
5.1建立职工表 职工工资表
#职工表
CREATE TABLE worker (
id INT AUTO_INCREMENT PRIMARY KEY NOT NULL,
name VARCHAR(40) NOT NULL,
sex VARCHAR(4) NOT NULL,
age INT NOT NULL
);
#职工工资表
CREATE TABLE wage (
id INT AUTO_INCREMENT PRIMARY KEY NOT NULL,
name VARCHAR(20) NOT NULL,
salary DOUBLE(10,2)
);
5.2建立添加触发器
CREATE TRIGGER worker_insert_trigger
AFTER INSERT ON worker
FOR EACH ROW
BEGIN
INSERT INTO wage VALUES (NULL,new.name,10000);
END;
5.3建立修改触发器
CREATE TRIGGER worker_update_trigger
AFTER UPDATE ON worker
FOR EACH ROW
BEGIN
UPDATE wage SET name = new.name WHERE name = old.name;
END;
5.4建立删除触发器
CREATE TRIGGER worker_delete_trigger
AFTER DELETE ON worker
FOR EACH ROW
BEGIN
DELETE FROM wage WHERE name = old.name;
END;
第八章 MySQL事务和SQL优化
1 什么是事务
Transaction,使我们数据库内最小且不可再分的单元。通常一个事务对应一个完整的业务(例如银行账户转账业务,该业务就是一个最小的工作单元)。一个完整的业务需要批量的DML(INSERT 、UPDATE、DELETE)语句共同联合完成。事务只和DML语句有关,或者说DML语句才有事务。这个和业务逻辑有关,业务逻辑不同,DML语句的个数不同。
操作序列范畴,这些序列共有的一个特征 要么全部执行,要么全都不执行。这是一个不可分割的工作单元。事务是由事务开始和事务结束之间所执行的数据库操作组成。
#例如以银行转账需求:
家长账户 扣款 -money 学生账户 收款 +money
必要要求 以上两台DML语句必须同时成功或者同时失败。最小单元不可再分,当第一条DML语句执行成功后,并不能将底层数据库中的第一个账户的数据修改,只是将操作进行了记录。这个记录实在内存中完成的,当第二条DML语句执行成功后,和底层数据库文件中的数据再进行完全的同步。反之如果第二条DML语句执行失败,清空所有的历史操作记录,以保证数据的统一。
事务处理(事务操作):保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,只有事务完成了提交行为。才意味着数据被永久的保存。
要么数据库管理系统将放弃所有的修改。使整个事务回滚到最初状态。
2 事务的特征
事务的本质是由一组SQL语句组成的逻辑处理单元。
A (原子性Atomicity):原子性是指事务是一个不可分割的最小单元,事务中的操作要么都发生,要么都不发生。
C (一致性Consistency):事务必须使数据库从一个一致性,转变到另一个一致性的状态。
I (隔离性Isolation):多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他的事务操作所干扰,要求多个并发事务之间 要相互隔离
D(持久性Durability):持久性指一个事务被提交是,它对于数据库内数据的改变就是永久性的,接下来即便数据库发生故障,也不应该对其有任何影响。
3 MySQL使用事务
实现
1、手动关闭掉一个操作 >>>>>>> 自动提交改变成手动提交
SET AUTOCOMMIT = 0;
2、标记事务的起点
START TRANSACTION
3、编辑并执行 SQL语句 组
4、提交
COMMIT
[5 、回滚
ROLLBACK]
6、手动开启掉一个操作 >>>>>>> 手动提交改变成自动提交
SET AUTOCOMMIT = 0;
实现截图
MySQL 开启事务,回滚,提交。
begin 5.5 以上版本 不需要手动begin,只要你执行的是一个DML,那么它就会自动在前面加入begin命令 COMMIT 提交事务 完成了一个事务,一旦事务提交成功,就说明具备了ACID原则 ROLLBACK 回滚职务 完成了一个事务,将内存中已执行的操作撤销,并还原成最初状态
示例演示:
#需求 顾客A在线购买了一个商品 价格XXXX元 采用转账方式进行支付 #假设A 存款金额XXXX元,且向卖家B支付购买商品费用 #卖家B 当前账户余额XXXX元 #步骤1:创建数据库 shop_db; CREATE DATABASE shop_db; #步骤2:创建账户表 账户编号(自增) 账户人 当前账户金额 CREATE TABLE IF NOT EXISTS `account` ( `id` int(11) not null auto_increment, `name` varchar(32) not null, `cash` decimal(9,2) not null, PRIMARY KEY (`id`) ) ENGINE=InnoDB; #步骤3:通过事务完成转账业务 SET AUTOCOMMIT = 0; START TRANSACTION; UPDATE account set cash = cash - 1000 WHERE name = 'A'; UPDATE account set cash = cash + 1000 WHERE name = 'B'; COMMIT; #ROLLBACK SET AUTOCOMMIT = 1; #那么当两个事务打开同一个数据库(用户???),数据库原始余额为100;第一个事务将余额改为0,结束了; #当第二个事务又将余额-50,那么最后结果是多少? #死锁 必须等待1事务结束后 方可执行2事务内的操作
4 事务的隔离级别
多个线程开启各自事务操作数据库中数据时,数据库系统要负责隔离操作,以保证各个线程在获取数据时的准确性。
如果不考虑隔离性:
1、 幻读
2、 脏读
3、不可重复读
幻读
在一个事务内读取到了别的事务插入的数据,导致前后读取的信息不一致
事务A按照自身的约定在进行数据读取,期间事务B插入了相同的搜索条件的新数据,事务A再次按照原先约定条件进行读取时,发现了事务B插入的新数据,幻读。
会造成事务中先产生的锁,无法管理后加入满足条件的行。
如何解决
bin_log :产生数据一致性问题,在一个事务中,先对符合条件的目标行做变更,而在事务提交前,有新符合目标条件的加入。通过bin_log 恢复数据会将所有符合条件的目标行进行变更。
间隙锁:在两行记录间的空隙加上锁,防止新纪录的插入。
脏读
事务读取到另一个事务未提交的数据,解决方案 加入乐观锁。
不可重复读
不可重复读,是指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据
这是由于查询时系统中其他事务修改的提交而引起的。比如事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。
幻读和不可重复读两者区别
不可重复读 指同一条SQL查询到了不同的结果
幻读指 查询的结果行数不同
事务的隔离级别
描述 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
Read uncommitted | 是 | 是 | 是 |
Read committed | 否 | 是 | 是 |
Repeatable read | 否 | 否 | 是 |
Serializable | 否 | 否 | 否 |
5 数据库优化
5.1 影响性能因素的优化
服务优化 硬件 操作系统 网络 数据库设计 应用优化 应用程序 查询 事务管理 数据分布
5.2 谁参与优化
数据库管理员> 业务部门代表> 架构师> 应用程序设计开发人员> 硬件及系统管理员> 存储管理员。。。
5.3 系统优化
软件优化 开发系统(操作系统) MYSQL编译优化 硬件优化 CPU 内存 硬盘 网卡
5.4 服务优化
Mysql配置 配置合理的Mysql服务器,尽量在应用本身达到一个合理的使用 针对于不同的搜索引擎,定制不同的配置 针对于不同的情况和需求,进行合理的配置 my.cnf进行配置。
5.5 MyISAM配置项
选项 | 缺省值 | 推荐值 | 说明 |
---|---|---|---|
key_buffer_size | 8M | 128M--256M | 用来存放索引区块的缓存值, 建议128M以上,不要大于内存的30% |
read_buffer_size | 128k | 10-20M | 用来做MyISAM表全表扫描的缓冲大小. |
myisam_sort_buffer_size | 16M | 128M | 设置,恢复,修改表的时候使用的缓冲大小 |
5.6 InnoDB配置项
选项 | 缺省值 | 推荐值 | 说明 |
---|---|---|---|
innodb_buffer_pool_size | 32M | 1G | InnoDB使用一个缓冲池来保存索引和原始数据, 这里你设置越大,你在存取表里面数据时所需要的磁盘I/O越少,一般是内存的一半,不超过2G,否则系统会崩溃,这个参数非常重要 |
innodb_additional_mem_pool_size | 2M | 128M | InnoDB用来保存 metadata 信息,如果内存是4G,最好本值超过200M |
innodb_flush_log_at_trx_commit | 1 | 0 | 0 代表日志只大约每秒写入日志文件并且日志文件刷新到磁盘; 1 为执行完没执行一条SQL马上commit; 2代表日志写入日志文件在每次提交后,但是日志文件只有大约每秒才会刷新到磁盘上. 对速度影响比较大,同时也关系数据完整性 |
innodb_log_file_size | 8M | 128M | 在日志组中每个日志文件的大小, 一般是innodb_buffer_pool_size的25%,官方推荐是innodb_buffer_pool_size 的 40-50%, 设置大一点来避免在日志文件覆写上不必要的缓冲池刷新行为 |
innodb_log_buffer_size | 128K | 8M | 用来缓冲日志数据的缓冲区的大小.推荐是8M,官方推荐该值小于16M,最好是 1M-8M 之间 |
5.7 应用优化
库表设计原则 选择合适的数据类型:如果能够定长尽量定长 使用 ENUM 而不是 VARCHAR,ENUM类型是非常快和紧凑的,在实际上,其保存的是 TINYINT,但其 外表上显示为字符串。这样一来,用这个字段来做一些选项列表变得相当的完美 。 不要使用无法加索引的类型作为关键字段,比如 text类型 为了避免联表查询,有时候可以适当的数据冗余,比如邮箱、姓名这些不容易更改的数据 选择合适的表引擎,有时候 MyISAM 适合,有时候InnoDB适合 为保证查询性能,最好每个表都建立有 auto_increment 字段, 建立合适的数据库索引 最好给每个字段都设定 default 值 索引建立原则(一) 一般针对数据分散的关键字进行建立索引,比如ID、QQ,• 像性别、状态值等等建立索引没有意义字段唯一,最少,不可为null 对大数据量表建立聚集索引,避免更新操作带来的碎片。 尽量使用短索引,一般对int、char/varchar、date/time 等类型的字段建立索引 需要的时候建立联合索引,但是要注意查询SQL语句的编写 谨慎建立 unique 类型的索引(唯一索引) 大文本字段不建立为索引,如果要对大文本字段进行检索, 可以考虑全文索引(引擎问题)频繁更新的列不适合建立索引 索引建立原则(二) order by 字句中的字段,where 子句中字段,最常用的sql语句中字段,应建立索引。 唯一性约束,系统将默认为改字段建立索引。 对于只是做查询用的数据库索引越多越好,但对于在线实时系统建议控制在5个以内。 索引不仅能提高查询SQL性能,同时也可以提高带where字句的update,Delete SQL性能。 Decimal 类型字段不要单独建立为索引,但覆盖索引可以包含这些字段。 只有建立索引以后,表内的行才按照特地的顺序存储,按照需要可以是asc或desc方式。 如果索引由多个字段组成将最用来查询过滤的字段放在前面可能会有更好的性能。 编写高效的 SQL (一) 能够快速缩小结果集的 WHERE 条件写在前面,如果有恒量条件,也尽量放在前面 尽量避免使用 GROUP BY、DISTINCT 、OR、IN 等语句的使用,避免使用联表查询和子查询, 因为将使执行效率大大下降 能够使用索引的字段尽量进行有效的合理排列,如果使用了联合索引,请注意提取字段的前后顺序 针对索引字段使用 >, >=, =, <, <=, IF NULL和BETWEEN 将会使用索引, 如果对某个索引字段进行 LIKE 查询,使用 LIKE ‘%abc%’不能使用索引,使用 LIKE ‘abc%’ 将能够使用索引 如果在SQL里使用了MySQL部分自带函数,索引将失效, 同时将无法使用 MySQL 的 Query Cache, 比如 LEFT(), SUBSTR(), TO_DAYS(),DATE_FORMAT(), 等, 如果使用了 OR 或 IN,索引也将失效 使用 Explain 语句来帮助改进我们的SQL语句 编写高效的 SQL (二) 不要在where 子句中的“=”左边进行算术或表达式运算,否则系统将可能无法正确使用索引 尽量不要在where条件中使用函数,否则将不能使用索引 避免使用 select *, 只取需要的字段 对于大数据量的查询,尽量避免在SQL语句中使用order by 字句,避免额外的开销 如果插入的数据量很大,用select into 替代 insert into 能带来更好的性能 采用连接操作,避免过多的子查询,产生的CPU和IO开销 只关心需要的表和满足条件的数据 适当使用临时表或表变量 对于连续的数值,使用between代替in where 字句中尽量不要使用CASE条件 尽量不用触发器,特别是在大数据表上 更新触发器如果不是所有情况下都需要触发,应根据业务需要加上必要判断条件 使用union all 操作代替OR操作,注意此时需要注意一点查询条件可以使用聚集索引, 如果是非聚集索引将起到相反的结果 当只要一行数据时使用 LIMIT 1 尽可能的使用 NOT NULL填充数据库 拆分大的 DELETE 或 INSERT 语句 批量提交SQL语句