mysql5.6

5.6 与之后版本有差别本文以5.6为例**

1.mysql5.6安装

本文采用2进制安装

mkdir /server/tools -p
cd /server/tools

1.下载

wget https://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.45-linux-glibc2.12-x86_64.tar.gz

2.解压到指定目录

tar xf mysql-5.6.45-linux-glibc2.12-x86_64.tar.gz -C /application/

3.重命名

mv mysql-5.6.45-linux-glibc2.12-x86_64 mysql
mkdir logs
mkdir data 

4.创建虚拟用户管理

useradd -M -s /sbin/nologin mysql
chown -R mysql.mysql /application/mysql

5.初始化数据

/application/mysql/scripts/mysql_install_db --basedir=/application/mysql --datadir=/application/mysql/data --user=mysql

6.配置启动脚本

cp /application/mysql/support-files/mysql.server  /etc/init.d/mysqld
chmod +x /etc/init.d/mysqld 
sed -i 's#/usr/local/mysql#/application/mysql#g' /application/mysql/bin/mysqld_safe /etc/init.d/mysqld

7.加入环境变量

echo 'export PATH=/application/mysql/bin:$PATH' >>/etc/profile
source /etc/profile

8.更改配置字文件

[mysqld]
basedir=/application/mysql
datadir=/application/mysql/data
port=3306
socket=/tmp/mysql.sock
#pid-file=/application/mysql/python.pid
log-error=/application/mysql/logs/error.log #启动时报错是需要创建
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
character_set_server = utf8

[client]
default-character-set = utf8

9.创建用户和密码

/etc/init.d/mysqld start  #启动   
mysqladmin -uroot password "23123"    #创建用户和 密码
mysql -uroot -p   #进入

10.加入开启及自启动

chkconfig --add mysqld 
chkconfig mysqld on

11.数据库连接管理

-u 指定用户
-p  密码
-h 地址
--protocol= 协议
-P 端口
-S 指定  套接字   scket文件 #socket = IP address + TCP/UDP +port
-e 执行命令

2.mysql多实例配置

使用场景,公司测试服务器 有mysql5.6,5.7,5.8一台服务器只建立一个数据库太费资源

思路

  1. 多套配置文件
  2. 多套数据
  3. 多个socket
  4. 多个端口
  5. 多个日志文件
  6. 多套启动程序
路径:
/data/3307/
/data/3308/
/data/3309/
配置文件
/data/3307/my.cnf
/data/3308/my.cnf
/data/3309/my.cnf
错误日志
/data/3307/mysql.log
/data/3308/mysql.log
/data/3309/mysql.log
二进制日志
/data/3307/mysql-bin
/data/3308/mysql-bin
/data/3309/mysql-bin
数据路径
/data/3307/data
/data/3308/data
/data/3309/data

创建相应目录:
mkdir -p /data/3307/data
mkdir -p /data/3308/data
mkdir -p /data/3309/data

编辑配置文件
vim /data/3307/my.cnf
[mysqld]
basedir=/application/mysql
datadir=/data/3307/data
socket=/data/3307/mysql.sock
port=3307
log-error=/data/3307/mysql.log
log_bin=/data/3307/mysql-bin
binlog_format=row
skip-name-resolve
server-id=7


--------------------------
vim /data/3308/my.cnf

[mysqld]
basedir=/application/mysql
datadir=/data/3308/data
port=3308
socket=/data/3308/mysql.sock
log-error=/data/3308/mysql.log
log_bin=/data/3308/mysql-bin
binlog_format=row
skip-name-resolve
server-id=8


------------------
vim /data/3309/my.cnf


[mysqld]
basedir=/application/mysql
datadir=/data/3309/data
socket=/data/3309/mysql.sock
port=3309
log-error=/data/3309/mysql.log
log_bin=/data/3309/mysql-bin
binlog_format=row
skip-name-resolve
server-id=9

------------------
初始化三套数据:
/application/mysql/scripts/mysql_install_db --user=mysql --basedir=/application/mysql --datadir=/data/3307/data
/application/mysql/scripts/mysql_install_db --user=mysql --basedir=/application/mysql --datadir=/data/3308/data
/application/mysql/scripts/mysql_install_db --user=mysql --basedir=/application/mysql --datadir=/data/3309/data


修改权限:

touch /data/330{7..9}/mysql.log
chown -R mysql.mysql /data/330*


启动数据库:
/application/mysql/bin/mysqld_safe --defaults-file=/data/3307/my.cnf &
/application/mysql/bin/mysqld_safe --defaults-file=/data/3308/my.cnf &
/application/mysql/bin/mysqld_safe --defaults-file=/data/3309/my.cnf &

验证:
netstat -lnp|grep 330

连接测试:
mysql -S /data/3307/mysql.sock -e "show variables like 'server_id'"
mysql -S /data/3308/mysql.sock -e "show variables like 'server_id'"
mysql -S /data/3309/mysql.sock -e "show variables like 'server_id'"

3.mysql用户管理

1.mysql登录权限

#进入mysql客户端
$mysql
mysql> select user();  #查看当前用户
mysql> exit     # 也可以用q quit退出

# mysql5.6默认是没有密码的
$ mysql -uroot -p   #遇到password直接按回车键
mysql> set password = password('root'); # 给当前数据库设置密码
mysqladmin -u root password '1233' #或者mysqladmin

#修改密码
alter user root@'localhost' identified by '123456';

#修改用户
rename user '用户名'@'IP地址' to '新用户名'@'IP地址';

# 创建账号
mysql> create user 'zbb'@'192.168.10.5' identified by  '123'  # 指示某机器可以连接  192.168.10.% # 指示网段  %  #指示所有机器都可以连接        
# 远程登陆
$ mysql -uroot -p123 -h 192.168.10.3
#删除用户:
mysql> drop user zxy@'10.0.0.52';
Query OK, 0 rows affected (0.07 sec)

#特殊删除
mysql> delete from mysql.user where user='zxy' and host='172.16.1.%';
Query OK, 1 row affected (0.05 sec)
#刷新授权表

mysql> flush privileges; #重新读取授权表,使权限更新
Query OK, 0 rows affected (0.00 sec)

2.给账号授权数据库

库级别

(1)全库级别:*.*

(2)单库级别:t.*

(3)单表级别:t.t1

增删改查权限

all,不包含grant和revoke

INSERT,SELECT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN,        

PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER,        

CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE,       

REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER       ROUTINE,

CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE

操作实例

mysql> grant all on *.* to 'zbb'@'%';
#5.6之后
grant all  on *.* to root@'%' with grant option;
mysql> flush privileges;    # 刷新使授权立即生效

#查看某个用户的权限 
mysql> show grants for 'zbb'@'192.168.10.5';

#收回权限
revoke all  on *.* from "zbb"@'10.0.0.5%';    收回

# 创建账号并授权 注意5.6之后分开了
mysql> grant all on *.* to 'zbb'@'%' identified by '123' 

4.忘记密码怎么办?

mysql5.6

5.6
/application/mysql/bin/mysqld_safe --skip-grant-tables --skip-networking &

update mysql.user set password=PASSWORD('123') where user='oldboy' and host='10.0.0.%';


select user,password,host from mysql.user;

mysql5.7

5.7以后
select user,authentication_string,host from mysql.user;
update mysql.user set authentication_string=PASSWORD('123') where user='oldboy' and host='10.0.0.%';

5.字符集

1.定义

是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等

MySQL数据库的字符集:

  • 字符集(CHARACTER)
  • 校对规则(COLLATION)

MySQL中常见的字符集:

  • UTF8
  • LATIN1
  • GBK

常见校对规则:

  • ci: 大小写不敏感
  • cs 或 bin 大小写敏感

查看字符集和校对规则

show charset;
show collation;

查看操作系统的字符集级别

echo $LANG

建立数据库时要确定字符集

[mysqld]
character-set-server=utf8

6.SQL语言分为3种类型:

SQL语言主要用于存取数据、查询数据、更新数据和管理关系数据库系统,SQL语言由IBM开发。

  1、DDL语句 数据库定义语言: 数据库、表、视图、索引、存储过程,例如CREATE DROP ALTER

  2、DML语句 数据库操纵语言: 插入数据INSERT、删除数据DELETE、更新数据UPDATE、查询数据SELECT

  3、DCL语句 数据库控制语言: 例如控制用户的访问权限GRANT、REVOKE

1. 操作文件夹(库)
   增:create database db1 charset utf8; #创建库指定字符集
   查:show databases
   改:alter database db1 charset latin1;#修改库的字符集
   删除: drop database db1;              #删库跑路


2. 操作文件(表)
   先切换到文件夹下:use db1
   增:create table t1(id int,name char); #建表
   查:show tables;
   改:alter table t1 modify name char(3);#修改表name列的字符长度
      alter table t1 change name name1 char(2);#同上
   删:drop table t1;                   #删表
    

3. 操作文件中的内容(记录)
   增:insert into t1 values(1,'1'),(2,'2'),(3,'3');#插入1行1列key,values
   #into  可以不写 
   查:select * from t1;
   改:update t1 set name='sb' where id=2; #更改id为2的values
   删:delete from t1 where id=1;  #删除id为1的行

   清空表:
       delete from t1; #如果有自增id,新增的数据,仍然是以删除前的最后一样作为起始。
       truncate table t1;数据量大,删除速度比上一条快,且直接从零开始,

*auto_increment 表示:自增
*primary key 表示:约束(不能重复且不能为空);加速查找

7.mysql中的储存引擎

mysql支持哪些存储引擎?

  mysql支持的存储引擎包括InnoDB、MyISAM、MEMORY、CSV、BLACKHOLE、FEDERATED、ARCHIVE、Merge、Examle。

InnoDB提供事务安全表,其他存储引擎都是非事务安全表。

储存引擎

查询支持的引擎

show engines

8.mysql中的数据类型

MySQL支持所有标准SQL数值数据类型。

这些类型包括严格数值数据类型(INTEGER、SMALLINT、DECIMAL和NUMERIC),以及近似数值数据类型(FLOAT、REAL和DOUBLE PRECISION)。

关键字INT是INTEGER的同义词,关键字DEC是DECIMAL的同义词。

MySQL支持的整数类型有TINYINT、MEDIUMINT和BIGINT。下面的表显示了需要的每个整数类型的存储和范围。

对于小数的表示,MYSQL分为两种方式:浮点数和定点数。浮点数包括float(单精度)和double(双精度),而定点数只有decimal一种,在mysql中以字符串的形式存放,比浮点数更精确,适合用来表示货币等精度高的数据。

BIT数据类型保存位字段值,并且支持MyISAM、MEMORY、InnoDB和BDB表。

将mysql模式改为严格模式

会有一个约束效果,超过范围会报错 在严格模式下

查看模式 严格,宽松模式

select @@global.sql_modeG;

STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION

模式设置和修改

**方式一**:
先执行select @@sql_mode,复制查询出来的值并将其中的NO_ZERO_IN_DATE,NO_ZERO_DATE删除
然后执行set sql_mode = '修改后的值'
例如:set  sql_mode='STRICT_TRANS_TABLES';改为严格模式

此方法只在当前会话中生效,关闭当前会话就不生效了。

**方式二**:
先执行select @@global.sql_mode,复制查询出来的值并将其中的NO_ZERO_IN_DATE,NO_ZERO_DATE删除,然后执行set global sql_mode = '修改后的值'。

此方法在当前服务中生效,重新MySQL服务后失效
**方法三**:

在mysql的安装目录下,或my.cnf文件(windows系统是my.ini文件),新增 sql_mode = ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,

    添加my.cnf如下:

    [mysqld]
sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER

然后重启mysql。

此方法永久生效.当然生产环境上是禁止重启MySQL服务的,所以采用方式二加方式三来解决线上的问题,那么即便是有一天真的重启了MySQL服务,也会永久生效了。

1.数值类型

类型 大小 范围(有符号) 范围(无符号)unsigned约束 用途
TINYINT 1 字节 (-128,127) (0,255) 小整数值
SMALLINT 2 字节 (-32 768,32 767) (0,65 535) 大整数值
MEDIUMINT 3 字节 (-8 388 608,8 388 607) (0,16 777 215) 大整数值
INT或INTEGER 4 字节 (-2 147 483 648,2 147 483 647) (0,4 294 967 295) 大整数值
BIGINT 8 字节 (-9 233 372 036 854 775 808,9 223 372 036 854 775 807) (0,18 446 744 073 709 551 615) 极大整数值
FLOAT 4 字节float(255,30)总长度255 ,小数点为30 (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) 0,(1.175 494 351 E-38,3.402 823 466 E+38) 单精度 浮点数值
DOUBLE 8 字节double(255,30) (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 双精度 浮点数值
DECIMAL 对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2double(65,30) 依赖于M和D的值 依赖于M和D的值 储存的是字符串 小数值

整形类型,其实没有必要指定显示宽度,使用默认的就ok

2.时间数据类型

表示时间值的日期和时间类型为DATETIME、DATE、TIMESTAMP、TIME和YEAR。

每个时间类型有一个有效值范围和一个"零"值,当指定不合法的MySQL不能表示的值时使用"零"值。

TIMESTAMP类型有专有的自动更新特性,将在后面描述。

类型 大小 (字节) 范围 格式 用途
DATE 3 1000-01-01/9999-12-31 YYYY-MM-DD 年月日
TIME 3 '-838:59:59'/'838:59:59' HH:MM:SS 时分秒
YEAR 1 1901/2155 YYYY 年份值
DATETIME 8 1000-01-01 00:00:00/9999-12-31 23:59:59 YYYY-MM-DD HH:MM:SS 年月日时分秒
TIMESTAMP 4 1970-01-01 00:00:00/2038结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 YYYYMMDD HHMMSS 混合日期和时间值,时间戳

3.字符串类型

字符串类型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。该节描述了这些类型如何工作以及如何在查询中使用这些类型。

类型 大小 用途
CHAR 0-255字节 定长字符串
VARCHAR 0-65535 字节 变长字符串
TINYBLOB 0-255字节 不超过 255 个字符的二进制字符串
TINYTEXT 0-255字节 短文本字符串
BLOB 0-65 535字节 二进制形式的长文本数据
TEXT 0-65 535字节 长文本数据
MEDIUMBLOB 0-16 777 215字节 二进制形式的中等长度文本数据
MEDIUMTEXT 0-16 777 215字节 中等长度文本数据
LONGBLOB 0-4 294 967 295字节 二进制形式的极大文本数据
LONGTEXT 0-4 294 967 295字节 极大文本数据

CHAR 和 VARCHAR 类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。

char:

优点:简单粗暴,不管你是多长的数据,我就按照规定的长度来存,5个5个的存,三个人名就会类似这种存储:sb ssb1 ssbb2,中间是空格补全,取数据的时候5个5个的取,简单粗暴速度快
缺点:貌似浪费空间,并且我们将来存储的数据的长度可能会参差不齐

varchar:

优点:节省了一些硬盘空间,一个acsii码的字符用一个bytes长度就能表示,但是也并不一定比char省,看一下官网给出的一个表格对比数据,当你存的数据正好是你规定的字段长度的时候,varchar反而占用的空间比char要多。
缺点:存取速度都慢

char 固定字符串长度 varchar 来多长的,我就给多少空间

长度小的用char 长的用varchar (基本都用char)

4.枚举类型与集合类型

单选 多选

字段的值只能在给定范围中选择,如单选框,多选框,如果你在应用程序或者前端不做选项限制,在MySQL的字段里面也能做限制
  enum 单选 只能在给定的范围内选一个值,如性别 sex 男male/女female
  set 多选 在给定的范围内可以选择一个或一个以上的值(爱好1,爱好2,爱好3...)

枚举类型(enum)
An ENUM column can have a maximum of 65,535 distinct elements. (The practical limit is less than 3000.)
示例:
CREATE TABLE shirts (
    name VARCHAR(40),
    size ENUM('x-small', 'small', 'medium', 'large', 'x-large') );

INSERT INTO shirts (name, size) VALUES ('dress shirt','large'), ('t-shirt','medium'),('polo shirt','small');

  
集合类型(set)
A SET column can have a maximum of 64 distinct members.
示例:
CREATE TABLE myset (col SET('a', 'b', 'c', 'd'));
INSERT INTO myset  VALUES ('a,d'), ('d,a'), ('a,d,a'), ('a,d,d'), ('d,a,d');

5.二进制字符串数据类型

BINARY 和 VARBINARY 类似于 CHAR 和 VARCHAR,不同的是它们包含二进制字符串而不要非二进制字符串。也就是说,它们包含字节字符串而不是字符字符串。这说明它们没有字符集,并且排序和比较基于列值字节的数值值。

BLOB 是一个二进制大对象,可以容纳可变数量的数据。有 4 种 BLOB 类型:TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。它们区别在于可容纳存储范围不同。

有 4 种 TEXT 类型:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。对应的这 4 种 BLOB 类型,可存储的最大长度不同,可根据实际情况选择。

6.如何选择数据类型

考虑哪些数据和字符集可以最大限度减少储存和磁盘I/O

使用固定长度数据类型:

  • 如果储存的所有字符串值的长度相同

使用可变长度数据类型:

  • 如果储存的字符串不通
  • 对于多字节字符集

对于频繁使用的字符,使用占用空间较小的多字节字符集.

  • 使用基本多文种平面,之外的其他Unicode字符集

9.表的完整性约束

为了防止不符合规范的数据进入数据库,在用户对数据进行插入、修改、删除等操作时,DBMS自动按照一定的约束条件对数据进行监测,使不符合规范的数据不能进入数据库,以确保数据库中存储的数据正确、有效、相容。

  约束条件与数据类型的宽度一样,都是可选参数,主要分为以下几种:

# NOT NULL :非空约束,指定某列不能为空; 
# UNIQUE : 唯一约束,指定某列或者几列组合不能重复
# PRIMARY KEY :主键,指定该列的值可以唯一地标识该列记录
# FOREIGN KEY :外键,指定该行记录从属于主表中的一条记录,主要用于参照完整性

1.NOT NULL

是否可空,null表示空,非字符串
not null - 不可空
null - 可空 默认的

mysql> create table t12(id int not null,name char(12)); #id不为空
Query OK, 0 rows affected (0.03 sec)

mysql> desc t12;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id    | int(11) | NO   |     | NULL    |       |
| name  | char(12) | YES  |     | NULL    |       |
+-------+---------+------+-----+---------+-------+
row in set (0.00 sec)

#不能向id列插入空元素。 
mysql> insert t12(id) values(null);
ERROR 1048 (23000): Column 'id' cannot be null

mysql> insert  t12(id) values(1);
Query OK, 1 row affected (0.00 sec)

DEFAULT

我们约束某一列不为空,如果这一列中经常有重复的内容,就需要我们频繁的插入,这样会给我们的操作带来新的负担,于是就出现了默认值的概念。

默认值,创建列时可以指定默认值,当插入数据时如果未主动设置,则自动添加默认值

not null + default

mysql> create table t13 (
    id1 int not null,
    id2 int not null default 222);
Query OK, 0 rows affected (0.01 sec) #222就是默认值

mysql> desc t13;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id1   | int(11) | NO   |     | NULL    |       |
| id2   | int(11) | NO   |     | 222     |       |
+-------+---------+------+-----+---------+-------+
rows in set (0.01 sec)

# 只向id1字段添加值,会发现id2字段会使用默认值填充
mysql> insert into t13 (id1) values (111);
Query OK, 1 row affected (0.00 sec)

mysql> select * from t13;
+-----+-----+
| id1 | id2 |
+-----+-----+
| 111 | 222 |
+-----+-----+
row in set (0.00 sec)

# id1字段不能为空,所以不能单独向id2字段填充值;
mysql> insert into t13 (id2) values (223);
ERROR 1364 (HY000): Field 'id1' doesn't have a default value

#向id1,id2中分别填充数据,id2的填充数据会覆盖默认值
mysql> insert into t13 (id1,id2) values (112,223);
Query OK, 1 row affected (0.00 sec)

mysql> select * from t13;
+-----+-----+
| id1 | id2 |
+-----+-----+
| 111 | 222 |
| 112 | 223 |
+-----+-----+
rows in set (0.00 sec)

not null不生效

设置严格模式:
    不支持对not null字段插入null值
    不支持对自增长字段插入”值
    不支持text字段有默认值

直接在mysql中生效(重启失效):
mysql>set sql_mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION";

配置文件添加(永久失效):
sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

not null不生效

2.UNIQUE

唯一约束,指定某列或者几列组合不能重复

Key(UNI)

1.unique示例

方法一:
create table department1(
    id int,
    name varchar(20) unique, #name不可重复
	comment varchar(100)
);


方法二:
create table department2(
	id int,
	name varchar(20),
	comment varchar(100),
	unique(name)
);


mysql> insert into department1 values(1,'IT','技术');
Query OK, 1 row affected (0.00 sec)
mysql> insert into department1 values(1,'IT','技术');
ERROR 1062 (23000): Duplicate entry 'IT' for key 'name'

2.not null 和unique的结合

Key(PRI)

mysql> create table t1(id int not null unique);
Query OK, 0 rows affected (0.02 sec)

mysql> desc t1;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id    | int(11) | NO   | PRI | NULL    |       |
+-------+---------+------+-----+---------+-------+
row in set (0.00 sec)

3.PRIMARY KEY

约束角度看primary key字段的值不为空且唯一,那我们直接使用not null+unique不就可以了吗,要它干什么?

主键primary key是innodb存储引擎组织数据的依据,innodb称之为索引组织表,一张表中必须有且只有一个主键。

一个表中可以:

​ 单列做主键
​ 多列做主键(复合主键或者叫做联合主键)

unique key和primary key都是MySQL的特殊类型,不仅仅是个字段约束条件,还称为索引,可以加快查询速度

在没有设置主键的时候,not null + unique 会被默认成为主键 UNI,在上面有提到Key

1.单字段主键

============单列做主键===============
#方法一:not null+unique
create table department1(
id int not null unique, #主键
name varchar(20) not null unique,
comment varchar(100)
);

mysql> desc department1;
+---------+--------------+------+-----+---------+-------+
| Field   | Type         | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id      | int(11)      | NO   | PRI | NULL    |       |
| name    | varchar(20)  | NO   | UNI | NULL    |       |
| comment | varchar(100) | YES  |     | NULL    |       |
+---------+--------------+------+-----+---------+-------+
rows in set (0.01 sec)

#方法二:在某一个字段后用primary key
create table department2(
id int primary key, #主键
name varchar(20),
comment varchar(100)
);

mysql> desc department2;
+---------+--------------+------+-----+---------+-------+
| Field   | Type         | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id      | int(11)      | NO   | PRI | NULL    |       |
| name    | varchar(20)  | YES  |     | NULL    |       |
| comment | varchar(100) | YES  |     | NULL    |       |
+---------+--------------+------+-----+---------+-------+
rows in set (0.00 sec)

#方法三:在所有字段后单独定义primary key
create table department3(
	id int,
	name varchar(20),
	comment varchar(100),
	primary key(id);

mysql> desc department3;
+---------+--------------+------+-----+---------+-------+
| Field   | Type         | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id      | int(11)      | NO   | PRI | NULL    |       |
| name    | varchar(20)  | YES  |     | NULL    |       |
| comment | varchar(100) | YES  |     | NULL    |       |
+---------+--------------+------+-----+---------+-------+
rows in set (0.01 sec)

# 方法四:给已经建成的表添加主键约束
mysql> create table department4(
    -> id int,
    -> name varchar(20),
    -> comment varchar(100));
Query OK, 0 rows affected (0.01 sec)

mysql> desc department4;
+---------+--------------+------+-----+---------+-------+
| Field   | Type         | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id      | int(11)      | YES  |     | NULL    |       |
| name    | varchar(20)  | YES  |     | NULL    |       |
| comment | varchar(100) | YES  |     | NULL    |       |
+---------+--------------+------+-----+---------+-------+
rows in set (0.01 sec)

mysql> alter table department4 modify id int primary key;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc department4;
+---------+--------------+------+-----+---------+-------+
| Field   | Type         | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id      | int(11)      | NO   | PRI | NULL    |       |
| name    | varchar(20)  | YES  |     | NULL    |       |
| comment | varchar(100) | YES  |     | NULL    |       |
+---------+--------------+------+-----+---------+-------+
rows in set (0.01 sec)

2.多字段主键

==================多列做主键================
create table service(
ip varchar(15),
port char(5),
service_name varchar(10) not null,
primary key(ip,port)
);


mysql> desc service;
+--------------+-------------+------+-----+---------+-------+
| Field        | Type        | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
| ip           | varchar(15) | NO   | PRI | NULL    |       |
| port         | char(5)     | NO   | PRI | NULL    |       |
| service_name | varchar(10) | NO   |     | NULL    |       |
+--------------+-------------+------+-----+---------+-------+
rows in set (0.00 sec)

mysql> insert into service values
    -> ('172.16.45.10','3306','mysqld'),
    -> ('172.16.45.11','3306','mariadb')
    -> ;
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> insert into service values ('172.16.45.10','3306','nginx');
ERROR 1062 (23000): Duplicate entry '172.16.45.10-3306' for key 'PRIMARY'

4.AUTO_INCREMENT

约束字段为自动增长,被约束的字段必须同时被key约束

#不指定id,则自动增长
create table student(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') default 'male'
);

mysql> desc student;
+-------+-----------------------+------+-----+---------+----------------+
| Field | Type                  | Null | Key | Default | Extra          |
+-------+-----------------------+------+-----+---------+----------------+
| id    | int(11)               | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20)           | YES  |     | NULL    |                |
| sex   | enum('male','female') | YES  |     | male    |                |
+-------+-----------------------+------+-----+---------+----------------+
mysql> insert into student(name) values
    -> ('egon'),
    -> ('alex')
    -> ;

mysql> select * from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | egon | male |
|  2 | alex | male |
+----+------+------+


#也可以指定id
mysql> insert into student values(4,'asb','female');
Query OK, 1 row affected (0.00 sec)

mysql> insert into student values(7,'wsb','female');
Query OK, 1 row affected (0.00 sec)

mysql> select * from student;
+----+------+--------+
| id | name | sex    |
+----+------+--------+
|  1 | egon | male   |
|  2 | alex | male   |
|  4 | asb  | female |
|  7 | wsb  | female |
+----+------+--------+


#对于自增的字段,在用delete删除后,再插入值,该字段仍按照删除前的位置继续增长
mysql> delete from student;
Query OK, 4 rows affected (0.00 sec)

mysql> select * from student;
Empty set (0.00 sec)

mysql> insert into student(name) values('ysb');
mysql> select * from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  8 | ysb  | male |
+----+------+------+

#应该用truncate清空表,比起delete一条一条地删除记录,truncate是直接清空表,在删除大表时用它
mysql> truncate student;
Query OK, 0 rows affected (0.01 sec)

mysql> insert into student(name) values('egon');
Query OK, 1 row affected (0.01 sec)

mysql> select * from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | egon | male |
+----+------+------+
row in set (0.00 sec)

设置auto_increment

了解

#在创建完表后,修改自增字段的起始值
mysql> create table student(
    -> id int primary key auto_increment,
    -> name varchar(20),
    -> sex enum('male','female') default 'male'
    -> );

mysql> alter table student auto_increment=3;

mysql> show create table student;
.......
ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8

mysql> insert into student(name) values('egon');
Query OK, 1 row affected (0.01 sec)

mysql> select * from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  3 | egon | male |
+----+------+------+
row in set (0.00 sec)

mysql> show create table student;
.......
ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8


#也可以创建表时指定auto_increment的初始值,注意初始值的设置为表选项,应该放到括号外
create table student(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') default 'male'
)auto_increment=3;




#设置步长
sqlserver:自增步长
    基于表级别
    create table t1(
        id int。。。
    )engine=innodb,auto_increment=2 步长=2 default charset=utf8

mysql自增的步长:
    show session variables like 'auto_inc%';
    
    #基于会话级别
    set session auth_increment_increment=2 #修改会话级别的步长

    #基于全局级别的
    set global auth_increment_increment=2 #修改全局级别的步长(所有会话都生效)


#!!!注意了注意了注意了!!!
If the value of auto_increment_offset is greater than that of auto_increment_increment, the value of auto_increment_offset is ignored. 
翻译:如果auto_increment_offset的值大于auto_increment_increment的值,则auto_increment_offset的值会被忽略 ,这相当于第一步步子就迈大了,扯着了蛋
比如:设置auto_increment_offset=3,auto_increment_increment=2




mysql> set global auto_increment_increment=5;
Query OK, 0 rows affected (0.00 sec)

mysql> set global auto_increment_offset=3;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like 'auto_incre%'; #需要退出重新登录
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| auto_increment_increment | 1     |
| auto_increment_offset    | 1     |
+--------------------------+-------+



create table student(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') default 'male'
);

mysql> insert into student(name) values('egon1'),('egon2'),('egon3');
mysql> select * from student;
+----+-------+------+
| id | name  | sex  |
+----+-------+------+
|  3 | egon1 | male |
|  8 | egon2 | male |
| 13 | egon3 | male |
+----+-------+------+

步长:auto_increment_increment,起始偏移量:auto_increment_offset

5.FOREI KEY

快速理解foreign key(外键其实就是标明表和表之间的关系,表和表之间如果有关系的话就三种:一对一,多对一,多对多,我们挨个看看~)

1.多对一关系

先创建 "一"表

create table publish(id int primary key auto_increment,name char(10));
mysql> desc publish;
+-------+----------+------+-----+---------+----------------+
| Field | Type     | Null | Key | Default | Extra          |
+-------+----------+------+-----+---------+----------------+
| id    | int(11)  | NO   | PRI | NULL    | auto_increment |
| name  | char(10) | YES  |     | NULL    |                |
+-------+----------+------+-----+---------+----------------+

在创建"多"表

create table book(id int primary key auto_increment,name char(10),pid int,foreign key(pid) references publish(id));

再插入出版社的数据

注意不能直接插入book数据 以为publish表的id为创建会报错

insert publish  values(1,'24出版社'),(2,'清华出版社'),(3,'红浪漫出版社');
mysql> select * from publish;
+----+--------------------+
| id | name               |
+----+--------------------+
|  1 | 24出版社           |
|  2 | 清华出版社         |
|  3 | 红浪漫出版社       |
+----+--------------------+
mysql> insert book values(1,'瓶梅',1); #这样最后一个数字1就有了
Query OK, 1 row affected (0.02 sec)

mysql> select * from book;
+----+-----------+------+
| id | name      | pid  |
+----+-----------+------+
|  1 | 瓶梅    |    1 |
+----+-----------+------+
1 row in set (0.00 sec)

删除,下面讲详细删除

mysql> delete from publish where id =1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`ddd`.`book`, CONSTRAINT `book_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `publish` (`id`))
#报错原因是说 publish这个表 有一个父级的外键,要先删除父才能删除子

2.一对一

只需要在一对多的基础上建立sublish表的时候 加上唯一

3.多对多

create table authortobook(
		id int primary key,
		author_id int,
		book_id int,
		foreign key(author_id) references author1(id),
		foreign key(book_id) references book1(id)
		);

4.删除外键

alter table book drop foreign key book_ibfk_1; #删除外键

alter table publish  drop id  #删除id行
#添加字段
alter table publish add id(字段名称) int(数据类型) primary key auto_increment(约束条件);
#创建表完成之后,再添加外键关系
alter table book add foreign key(pid) references publish(id);
 
#另外,能够作为主表(也就是多对一关系的那个一表的被关联的那个字段)的关系字段的约束最少要是唯一的unique属性。

5.级联

外键约束有三种约束模式(都是针对父表的约束):

    模式一: district 严格约束(默认的 ),父表不能删除或者更新已经被子表数据引用的记录

    模式二:cascade 级联模式:父表的操作,对应的子表关联的数据也跟着操作 。

    模式三:set null:置空模式,父表操作之后,子表对应的数据(外键字段)也跟着被置空。

    通常的一个合理的约束模式是:删除的时候子表置空;更新的时候子表级联。

    **指定模式的语法:foreign key(外键字段)references 父表(主键字段)on delete 模式 on **

update 模式;

alter table 从表 add foreign key(从表字段) references 主表(主表字段) on delete cascade on update cascade;

    注意:删除置空的前提条件是 外键字段允许为空,不然外键会创建失败。

    外键虽然很强大,能够进行各种约束,但是外键的约束降低了数据的可控性和可拓展性。通常在实际开发时,很少使用外键来约束。

我们可以自己从自己的程序代码的逻辑层面上将这些关联关系建立好

10.mysql表操作

表就相当于文件,表中的一条记录就相当于文件的一行内容,不同的是,表中的一条记录有对应的标题,称为表的字段

1.创建表

#语法:
create table 表名(
字段名1 类型[(宽度) 约束条件],
字段名2 类型[(宽度) 约束条件],
字段名3 类型[(宽度) 约束条件]
);

#注意:
1. 在同一张表中,字段名是不能相同
2. 宽度和约束条件可选
3. 字段名和类型是必须的

创建表结构

mysql> create database  tt1; #先建库
use tt1; #进入数据库

create  table t(id int(4),name varchar(50),age int(2),sex enum('male','female'),phone bigint(11),job varchar(12));#创建表

desc t; #查看表
+-------+-----------------------+------+-----+---------+-------+
| Field | Type                  | Null | Key | Default | Extra |
+-------+-----------------------+------+-----+---------+-------+
| id    | int(4)                | YES  |     | NULL    |       |
| name  | varchar(50)           | YES  |     | NULL    |       |
| age   | int(2)                | YES  |     | NULL    |       |
| sex   | enum('male','female') | YES  |     | NULL    |       |
| phone | bigint(11)            | YES  |     | NULL    |       |
| job   | varchar(12)           | YES  |     | NULL    |       |
+-------+-----------------------+------+-----+---------+-------+

2.添加表数据

insert  t values(1,'zbb',83,'female',18812345678,'IT');#插入数据
select * from t; #查看数据
+------+------+------+--------+-------------+------+
| id   | name | age  | sex    | phone       | job  |
+------+------+------+--------+-------------+------+
|    1 | zbb  |   83 | female | 18812345678 | IT   |
+------+------+------+--------+-------------+------+

3.查看表结构

两种方式

desc t; #查看表 查的不全面

直接查看建表语句

mysql> show   create table tG;
*************************** 1. row ***************************
       Table: t
Create Table: CREATE TABLE `t` (
  `id` int(4) DEFAULT NULL,
  `name` varchar(50) DEFAULT NULL,
  `age` int(2) DEFAULT NULL,
  `sex` enum('male','female') DEFAULT NULL,
  `phone` bigint(11) DEFAULT NULL,
  `job` varchar(12) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

4.修改表结构

语法:
1. 修改表名
      ALTER TABLE 表名 
                      RENAME 新表名;

2. 增加字段
      ALTER TABLE 表名
                      ADD 字段名  数据类型 [完整性约束条件…],
                      ADD 字段名  数据类型 [完整性约束条件…];
                            
3. 删除字段
      ALTER TABLE 表名 
                      DROP 字段名;

4. 修改字段
      ALTER TABLE 表名 
                      MODIFY  字段名 数据类型 [完整性约束条件…];
      ALTER TABLE 表名 
                      CHANGE 旧字段名 新字段名 旧数据类型 [完整性约束条件…];
      ALTER TABLE 表名 
                      CHANGE 旧字段名 新字段名 新数据类型 [完整性约束条件…];

5.修改字段排列顺序/在增加的时候指定字段位置
    ALTER TABLE 表名
                     ADD 字段名  数据类型 [完整性约束条件…]  FIRST;
    ALTER TABLE 表名
                     ADD 字段名  数据类型 [完整性约束条件…]  AFTER 字段名;

复制表

语法:复制表结构+记录 (key不会复制: 主键、外键和索引)
mysql> create table new_service select * from service;

这句话的意思是你从service表里面查询出来的数据不要在屏幕上打印了,你直接给我的新表new_service

只复制表结构,不要数据
mysql> select * from service where 1=2;

//条件为假,查不到任何记录,所以我们可以通过它来只复制表结构,看下面一句

mysql> create table new1_service select * from service where 1=2;

筛选数据的条件为假,那么只拿到了结构,并没有查询出任何的数据,所以做到了只复制表结构

alter操作非空和唯一(了解)

create table t(id int unique,name char(10) not null);

#去掉null约束
alter table t modify name char(10) null;
# 添加null约束
alter table t modify name char(10) not null;


# 去掉unique约束
alter table t drop index id;
# 添加unique约束
alter table t modify id int unique;

alter处理null和unique约束

alter操作主键(了解)

1、首先创建一个数据表table_test:
create table table_test(
`id` varchar(100) NOT NULL,
`name` varchar(100) NOT NULL,
PRIMARY KEY (`name`)
); 
2、如果发现主键设置错了,应该是id是主键,但如今表里已经有好多数据了,不能删除表再重建了,仅仅能在这基础上改动表结构。
先删除主键
alter table table_test drop primary key;
然后再增加主键
alter table table_test add primary key(id);
注:在增加主键之前,必须先把反复的id删除掉

为表添加外键(了解)

创建press表
CREATE TABLE `press` (
  `id` int(11) NOT NULL,
  `name` char(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ;

创建book表
CREATE TABLE `book` (
  `id` int(11) DEFAULT NULL,
  `bk_name` char(12) DEFAULT NULL,
  `press_id` int(11) NOT NULL,
  KEY `press_id` (`press_id`)
) ;

为book表添加外键
alter table book add constraint fk_id foreign key(press_id) references press(id);

删除外键
alter table book drop foreign key fk_id;

示例

mysql> desc  ttt; #查看表结构
+-------+-----------------------+------+-----+---------+-------+
| Field | Type                  | Null | Key | Default | Extra |
+-------+-----------------------+------+-----+---------+-------+
| id    | int(4)                | YES  |     | NULL    |       |
| name  | varchar(50)           | YES  |     | NULL    |       |
| age   | int(2)                | YES  |     | NULL    |       |
| sex   | enum('male','female') | YES  |     | NULL    |       |
| phone | bigint(11)            | YES  |     | NULL    |       |
| job   | varchar(12)           | YES  |     | NULL    |       |
| www   | char(1)               | YES  |     | NULL    |       |
+-------+-----------------------+------+-----+---------+-------+

mysql> alter table ttt rename  zbb; #修改表名为zbb
Query OK, 0 rows affected (0.03 sec)

mysql> alter table ttt rename  zbb;#删除名字为www的列
Query OK, 0 rows affected (0.03 sec)

mysql> alter table zbb add www char(12);#添加www的列
Query OK, 0 rows affected (0.12 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> alter table zbb modify id int(10);#修改id的宽度
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> alter table zbb change name sname varchar(20);
Query OK, 1 row affected (0.19 sec) #修改name列的字段名

mysql> alter table zbb  modify sex enum('male','female') after sname;#修改sex列的位置
Query OK, 0 rows affected (0.12 sec)


mysql> alter table zbb modify  id int(4) primary key auto_increment; #创建自增id主键
Query OK, 1 row affected (0.15 sec)
mysql> desc zbb;
+-------+-----------------------+------+-----+---------+----------------+
| Field | Type                  | Null | Key | Default | Extra          |
+-------+-----------------------+------+-----+---------+----------------+
| id    | int(4)                | NO   | PRI | NULL    | auto_increment |
| sname | varchar(20)           | YES  |     | NULL    |                |
| sex   | enum('male','female') | YES  |     | NULL    |                |
| age   | int(2)                | YES  |     | NULL    |                |
| phone | bigint(11)            | YES  |     | NULL    |                |
| job   | varchar(12)           | YES  |     | NULL    |                |
| www   | char(12)              | YES  |     | NULL    |                |
+-------+-----------------------+------+-----+---------+----------------+

# 删除主键,可以看到删除一个自增主键会报错
mysql> alter table zbb drop primary key;
ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key

# 需要先去掉主键的自增约束,然后再删除主键约束
mysql> alter table zbb modify id int(11);
mysql> alter table zbb drop primary key;

# 添加联合主键
mysql> alter table zbb add primary key (sname,age);


# 删除主键
mysql> alter table zbb drop primary key;


# 创建主键id
mysql> alter table zbb add primary key (id);
mysql> desc zbb;
+-------+-----------------------+------+-----+---------+-------+
| Field | Type                  | Null | Key | Default | Extra |
+-------+-----------------------+------+-----+---------+-------+
| id    | int(11)               | NO   | PRI | 0       |       |
| sname | varchar(20)           | NO   |     |         |       |
| sex   | enum('male','female') | YES  |     | NULL    |       |
| age   | int(2)                | NO   |     | 0       |       |
| phone | bigint(11)            | YES  |     | NULL    |       |
| job   | varchar(12)           | YES  |     | NULL    |       |
| www   | char(12)              | YES  |     | NULL    |       |
+-------+-----------------------+------+-----+---------+-------+


# 为主键添加自增属性
mysql> alter table zbb modify id int(4) auto_increment;
mysql> desc zbb;
+-------+-----------------------+------+-----+---------+----------------+
| Field | Type                  | Null | Key | Default | Extra          |
+-------+-----------------------+------+-----+---------+----------------+
| id    | int(4)                | NO   | PRI | NULL    | auto_increment |
| sname | varchar(20)           | NO   |     |         |                |
| sex   | enum('male','female') | YES  |     | NULL    |                |
| age   | int(2)                | NO   |     | 0       |                |
| phone | bigint(11)            | YES  |     | NULL    |                |
| job   | varchar(12)           | YES  |     | NULL    |                |
| www   | char(12)              | YES  |     | NULL    |                |
+-------+-----------------------+------+-----+---------+----------------+

11.mysql记录操作

1.增加insert

insert into 表名 values(字段1,字段2...); #into可以不写
insert into 表名(id,name) values(字段1,字段2),(xx1,xx2);#多条用,分割

将从表2里面查询出来的结果来插入到我们的表中,但是注意查询出来的数据要和我们前面指定的字段要

一一对应

INSERT INTO 表名(字段1,字段2,字段3…字段n) 
                SELECT (字段1,字段2,字段3…字段n) FROM 表2
                WHERE …; #where 不加就是全部

2.修改update

语法:
UPDATE 表名 SET 
    字段1=值1,  #注意语法,可以同时来修改多个值,用逗号分隔
    字段2=值2,
    WHERE 条件; #更改哪些数据,通过where条件来定位到符合条件的数据

示例:
UPDATE mysql.user SET password=password(‘123’) 
    where user=’root’ and host=’localhost’; 
#这句话是对myslq这个库中的user表中的user字段为'root'并且host字段为'localhost'的这条记录的password字段的数据进行修改,将passord字段的那个数据改为password('123')这个方法对123加工后的密码数据,password()这个方法是mysql提供的密码进行加密用的方法。

3.删除delete

delete from t3 #删除所有的数据,但是不会重置自增字段的id号
delete from t3 where id =1; #删除自定的id号的那一行数据
#清空表
truncate 表名; #自增字段会被重置 清空所有 只留表结构

12.查询select

1.单表查询

1.语法

select * from 库名.表名; #查询效率较低

select distinct(去重) 字段1,字段2  from 库名.表名
						where 条件 
						group by field(字段) #分组
						having(筛选)#过滤之后执行select后的字段筛选
						order by field(字段)#将结果按照后面的字段进行排序
						limit 限制条数#将最后的结果加上一个限制条件

2.优先级

from  #从
where  #约束条件
group by #分组
having #筛选
select  #执行
distinct #去重
order by #排序
limit  #限制条数

3.四则运算:

#as + 新字段名,就是起一个别名的意思,上面的那个salary*12的字段名也是一个别名,只不过不直观,是mysql自动给你写上的
SELECT name, salary*12 AS Annual_salary FROM employee; #加减乘除都可

4.自定义concat

CONCAT() 函数用于连接字符串

SELECT CONCAT('姓名: ',name,'  年薪: ', salary*12)  AS Annual_salary FROM employee;
SELECT CONCAT('姓名: ',name,'  年薪: ', salary*12)  AS Annual_salary,CONCAT('性别:',sex) from employee;#还可以这样分成两列 
CONCAT_WS() 第一个参数为分隔符来进行字符串拼接
SELECT CONCAT_WS(':',name,salary*12)  AS Annual_salary  #通过冒号来将name和salary连接起来
FROM employee;
#上面这个效果我们也可以通过concat来实现:
SELECT CONCAT(name,':',salary*12)  AS Annual_salary from employee;

5.where条件

  1. 比较运算符:> < >= <= <> !=
  2. between 80 and 100 值在80到100之间
  3. in(80,90,100) 值是80或90或100
  4. like 'egon%'

  pattern可以是%或_,
  %表示任意多字符
  _表示一个字符

  1. 逻辑运算符:在多个条件直接可以使用逻辑运算符 and or not
#多条件查询
select id age from tt
	where  sex='man' and age <50;
	
#关键字 between and 区间
select name,age from t
	where age between 10 and 20; #not  between 10 and 20 加not就是不在这个区间的
	
#关键字in集合查询
select name age from tt
	where age in (11,22,33); 

#关键字like模糊查询,可以结合通配符号使用
% #匹配所有字符
select * from tt
	where name like 'zb%'
_ #匹配任意一个字符 
select * from tt
	where name like 'zb_';

6.group by作用

明确一点:分组发生在where之后,即分组是基于where之后得到的记录而进行的

分组指的是:将所有记录按照某个相同字段进行归类

为何要分组呢?是因为我们有时候会需要以组为单位来统计一些数据或者进行一些计算的

可以按照任意字段分组,但是分组完毕后,比如group by post,只能查看post字段,如果想查看组内信息,需要借助于聚合函数

select * from tt group by sex; #默认都是拿到的第一条数据
将来你在这样进行直接分组查询的时候,可能因为你们公司设置的mysql的环境不同,而查不到数据,我们可以看到,我们现在仍然可以查询出来数据,
但是如果我们在sql_mode中添加了下面的only_full_group_by这个mode,那么我们在直接分组查询,就无法得到数据了,只能得到字段名
并且设置了sql_mode为only_full_group_by之后,select *,就不行了,会直接报错,只能select post ,post是你分组的那个字段

only_full_group_by

ONLY_FULL_GROUP_BY的语义就是确定select target list中的所有列的值都是明确语义,
简单的说来,在ONLY_FULL_GROUP_BY模式下,target list中的值要么是来自于聚集函数的结果,要么是来自于group by list中的表达式的值。

7.group by分组

只能查看分组依据和使用聚合函数

SELECT sex FROM employee GROUP BY sex;
#我们按照post字段分组,那么select查询的字段只能是post,想要获取组内的其他相关信息,需要借助函数
GROUP BY一般都会与聚合函数一起使用,聚合是什么意思:聚合就是将分组的数据聚集到一起,合并起来搞事情,拿到一个最后的结果
select sex,count(id) as count from tt group by sex;
#按照性别分组 记录每个组有多少人
GROUP BY关键字和GROUP_CONCAT()函数一起使用,比如说我想按部门分组,每个组有哪些员工,都显示出来,怎么搞
SELECT post,GROUP_CONCAT(name) FROM employee GROUP BY post;#按照岗位分组,并查看组内所有成员名,通过逗号拼接在一起
SELECT post,GROUP_CONCAT(name,':',salary) as emp_members FROM employee GROUP BY post;

8.聚合函数

mysql提供了以下几种聚合函数:count、max、min、avg、sum group_concat(做字符串拼接的操作)

9.过滤having

having的语法格式和where是一模一样的,只不过having是在分组之后进行的进一步的过滤,where不能使用聚合函数,having是可以使用聚合函数的#!!!执行优先级从高到低:where > group by > having 

1. Where 发生在分组group by之前,因而Where中可以有任意字段,但是绝对不能使用聚合函数。

2. Having发生在分组group by之后,因而Having中可以使用分组的字段,无法直接取到其他字段,having是可以使用聚合函数
select sex,max(age) from tt group by sex having max(age)>20;

10.去重distinct

有时需要查询出某个字段不重复的记录,这时可以使用mysql提供的distinct这个关键字来过滤重复的记录,但是实际中我们往往用distinct来返回不重复字段的条数(count(distinct id)),其原因是distinct只能返回他的目标字段,而无法返回其他字段,distinct 想写在其他字段后面需要配合聚合函数来写。

mysql> select id,count(distinct post) from employee;
ERROR 1140 (42000): Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause
报错了:是因为distinct不能返回其他的字段,只能返回目标字段
mysql> select count(distinct post) from employee;
+----------------------+
| count(distinct post) |
+----------------------+
|                    4 |
+----------------------+
row in set (0.00 sec)

11.排序

示例:
	select * from tt order by age;
	select * from tt order by age asc;
	上面这两种写法都是按照age字段来进行升序排列
	select * from tt order by age desc;
	desc是降序排列
	
多条件排序
	按照age字段升序,age相同的数据,按照salary降序排列
	select * from tt order by age asc ,salary desc;

12.限制查询条数limit

SELECT * FROM employee ORDER BY salary DESC 
    LIMIT 3;                    #默认初始位置为0,从第一条开始顺序取出三条 
    
SELECT * FROM employee ORDER BY salary DESC
    LIMIT 0,5; #从第0开始,即先查询出第一条,然后包含这一条在内往后查5条 

13.使用正则表查询

SELECT * FROM employee WHERE name REGEXP '^ale';

SELECT * FROM employee WHERE name REGEXP 'on$';

SELECT * FROM employee WHERE name REGEXP 'm{2}';


小结:对字符串匹配的方式
WHERE name = 'egon';
WHERE name LIKE 'yua%';
WHERE name REGEXP 'on$';

2.多表查询

1.迪卡尔积

笛卡尔积:将两表所有的数据一一对应,生成一张大表(效率很低一般不用)

select * from dep,emp;  #两个表拼一起
select * from dep,emp where dep.id = emp.dep_id; #找到两表之间对应的关系记录
select * from dep,emp where dep.id = emp.dep_id and dep.name='技术'; #筛选部门名称为技术的大表中的记录
select emp.name from dep,emp where dep.id = emp.dep_id and dep.name='技术'; #拿到筛选后的记录的员工姓名字段数据

2.连表查询

1.inner join 内连接

#第一步:连表
select * from dep inner join emp on dep.id = emp.dep_id;
#第二步:过滤
select * from dep inner join emp on dep.id=emp.dep_id where dep.name='技术';
#第三步:找对应字段数据
select emp.name from dep inner join emp on dep.id=emp.dep_id where dep.name='技术';

2.left join 左连接

左连接(left join左边的表为主表,主表记录必须全部显示,辅表没办法对应上的,就通过null来补全)

select * from dep left join emp on dep.id = emp.dep_id

3.right join 右连接

select * from dep right join emp on dep.id=emp.dep_id

4.union全连接

select * from dep left join emp dep.id=emp.dep_id 
union
select * from dep right join emp dep.id=emp.dep_id
#注意 union与union all的区别:union会去掉相同的纪录,因为union all是left join 和right join合并,所以有重复的记录,通过union就将重复的记录去重了

3.子查询

select name from emp where dep_id = (select id from dep where name = "技术");#where后面的只是条件
1:子查询是将一个查询语句嵌套在另一个查询语句中。
2:内层查询语句的查询结果,可以为外层查询语句提供查询条件。
3:子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字
4:还可以包含比较运算符:= 、 !=、> 、<等

1.带IN关键字的子查询

当返回值是多条数据时,不能使用 = 只用使用in

select name from employee where dep_id in (select id from department where name='技术');

2.带比较运算符的子查询

select name,age from emp where age >(select avg(age) from emp);

3.带exists关键字的子查询

EXISTS关字键字表示存在。在使用EXISTS关键字时,内层查询语句不返回查询的记录。而是返回一个真假值。True或False
当返回True时,外层查询语句将进行查询;当返回值为False时,外层查询语句不进行查询。还可以写not exists,和exists的效果就是反的

mysql> select * from employee
    ->     where exists
    ->         (select id from department where id=204);
Empty set (0.00 sec)

3.多表查询练习

#创建表及插入记录
CREATE TABLE class (
  cid int(11) NOT NULL AUTO_INCREMENT,
  caption varchar(32) NOT NULL,
  PRIMARY KEY (cid)
) ENGINE=InnoDB CHARSET=utf8;

INSERT INTO class VALUES
(1, '三年二班'), 
(2, '三年三班'), 
(3, '一年二班'), 
(4, '二年九班');

CREATE TABLE course(
  cid int(11) NOT NULL AUTO_INCREMENT,
  cname varchar(32) NOT NULL,
  teacher_id int(11) NOT NULL,
  PRIMARY KEY (cid),
  KEY fk_course_teacher (teacher_id),
  CONSTRAINT fk_course_teacher FOREIGN KEY (teacher_id) REFERENCES teacher (tid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO course VALUES
(1, '生物', 1), 
(2, '物理', 2), 
(3, '体育', 3), 
(4, '美术', 2);

CREATE TABLE score (
  sid int(11) NOT NULL AUTO_INCREMENT,
  student_id int(11) NOT NULL,
  course_id int(11) NOT NULL,
  num int(11) NOT NULL,
  PRIMARY KEY (sid),
  KEY fk_score_student (student_id),
  KEY fk_score_course (course_id),
  CONSTRAINT fk_score_course FOREIGN KEY (course_id) REFERENCES course (cid),
  CONSTRAINT fk_score_student FOREIGN KEY (student_id) REFERENCES student(sid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO score VALUES
(1, 1, 1, 10),
(2, 1, 2, 9),
(5, 1, 4, 66),
(6, 2, 1, 8),
(8, 2, 3, 68),
(9, 2, 4, 99),
(10, 3, 1, 77),
(11, 3, 2, 66),
(12, 3, 3, 87),
(13, 3, 4, 99),
(14, 4, 1, 79),
(15, 4, 2, 11),
(16, 4, 3, 67),
(17, 4, 4, 100),
(18, 5, 1, 79),
(19, 5, 2, 11),
(20, 5, 3, 67),
(21, 5, 4, 100),
(22, 6, 1, 9),
(23, 6, 2, 100),
(24, 6, 3, 67),
(25, 6, 4, 100),
(26, 7, 1, 9),
(27, 7, 2, 100),
(28, 7, 3, 67),
(29, 7, 4, 88),
(30, 8, 1, 9),
(31, 8, 2, 100),
(32, 8, 3, 67),
(33, 8, 4, 88),
(34, 9, 1, 91),
(35, 9, 2, 88),
(36, 9, 3, 67),
(37, 9, 4, 22),
(38, 10, 1, 90),
(39, 10, 2, 77),
(40, 10, 3, 43),
(41, 10, 4, 87),
(42, 11, 1, 90),
(43, 11, 2, 77),
(44, 11, 3, 43),
(45, 11, 4, 87),
(46, 12, 1, 90),
(47, 12, 2, 77),
(48, 12, 3, 43),
(49, 12, 4, 87),
(52, 13, 3, 87);


CREATE TABLE student(
  sid int(11) NOT NULL AUTO_INCREMENT,
  gender char(1) NOT NULL,
  class_id int(11) NOT NULL,
  sname varchar(32) NOT NULL,
  PRIMARY KEY (sid),
  KEY fk_class (class_id),
  CONSTRAINT fk_class FOREIGN KEY (class_id) REFERENCES class (cid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO student VALUES
(1, '男', 1, '理解'), 
(2, '女', 1, '钢蛋'), 
(3, '男', 1, '张三'), 
(4, '男', 1, '张一'), 
(5, '女', 1, '张二'), 
(6, '男', 1, '张四'), 
(7, '女', 2, '铁锤'), 
(8, '男', 2, '李三'), 
(9, '男', 2, '李一'), 
(10, '女', 2, '李二'), 
(11, '男', 2, '李四'), 
(12, '女', 3, '如花'), 
(13, '男', 3, '刘三'), 
(14, '男', 3, '刘一'), 
(15, '女', 3, '刘二'), 
(16, '男', 3, '刘四');

CREATE TABLE teacher(
  tid int(11) NOT NULL AUTO_INCREMENT,
  tname varchar(32) NOT NULL,
  PRIMARY KEY (tid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO teacher VALUES
(1, '张磊老师'), 
(2, '李平老师'), 
(3, '刘海燕老师'), 
(4, '朱云海老师'), 
(5, '李杰老师');

4.答案

1、查询所有的课程的名称以及对应的任课老师姓名
SELECT
	course.cname,
	teacher.tname 
FROM
	course
	INNER JOIN teacher ON teacher.tid = course.cid;

2、查询学生表中男女生各有多少人
select gender,count(sid)  from student  group by gender;
3、查询物理成绩等于100的学生的姓名
#先查询 获得成绩表的等于100的id
select  student_id from score inner join course on score.course_id = course.cid where course.cname = '物理' and score.num =100;
#完整的如下
SELECT
	sname 
FROM
	student 
WHERE
	sid IN (
	SELECT
		student_id 
	FROM
		score
		INNER JOIN course ON score.course_id = course.cid 
	WHERE
		course.cname = '物理' 
	AND score.num = 100 
	);

4、查询平均成绩大于八十分的同学的姓名和平均成绩
#先查出score表中的学生id和平均成绩
SELECT
	student_id,
	avg( num ) 
FROM
	score 
GROUP BY
	student_id 
HAVING
	avg( num )> 80;#太长了起一个别名   as t1
------------------------------------->完整的
SELECT
	student.sname,
	t1.avg_num 
FROM
	student
	INNER JOIN ( SELECT student_id, avg( num ) AS avg_num FROM score GROUP BY student_id HAVING avg( num ) > 80 ) AS t1 ON student.sid = t1.student_id;

5、查询所有学生的学号,姓名,选课数,总成绩

6、 查询姓李老师的个数

7、 查询没有报李平老师课的学生姓名

8、 查询物理课程比生物课程高的学生的学号

9、 查询没有同时选修物理课程和体育课程的学生姓名

10、查询挂科超过两门(包括两门)的学生姓名和班级

11 、查询选修了所有课程的学生姓名

12、查询李平老师教的课程的所有成绩记录
 
13、查询全部学生都选修了的课程号和课程名

14、查询每门课程被选修的次数

15、查询之选修了一门课程的学生姓名和学号

16、查询所有学生考出的成绩并按从高到低排序(成绩去重)

17、查询平均成绩大于85的学生姓名和平均成绩

18、查询生物成绩不及格的学生姓名和对应生物分数

19、查询在所有选修了李平老师课程的学生中,这些课程(李平老师的课程,不是所有课程)平均成绩最高的学生姓名

20、查询每门课程成绩最好的前两名学生姓名

21、查询不同课程但成绩相同的学号,课程号,成绩

22、查询没学过“叶平”老师课程的学生姓名以及选修的课程名称;

23、查询所有选修了学号为1的同学选修过的一门或者多门课程的同学学号和姓名;

24、任课最多的老师中学生单科成绩最高的学生姓名

13.mysql索引原理

1.索引定义

数据库索引好比是一本书前面的目录,能加快数据库的查询速度。索引是对数据库表中一个或多个列(例如,employee 表的姓氏 (lname) 列)的值进行排序的结构。如果想按特定职员的姓来查找他或她,则与在表中搜索所有的行相比,索引有助于更快地获取信息。

​ 查询数据库,按主键查询是最快的,每个表只能有一个主键列,但是可以有多个普通索引列,主键列要求所有内容必须唯一,而普通索引不要求内容必须唯一。

​ 集群因子:索引叶子节点获取数据大于真是数据时,索引没有意义

索引在MySQL中也叫做“键”或者"key"(primary key,unique key,还有一个index key),是存储引擎用于快速找到记录的一种数据结构。索引对于良好的性能非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发重要,减少io次数,加速查询。(其中primary key和unique key,除了有加速查询的效果之外,还有约束的效果,primary key 不为空且唯一,unique key 唯一,而index key只有加速查询的效果,没有约束效果)
    索引优化应该是对查询性能优化最有效的手段了。索引能够轻易将查询性能提高好几个数量级。
    索引相当于字典的音序表,如果要查某个字,如果不使用音序表,则需要从几百页中逐页去查。

    强调:一旦为表创建了索引,以后的查询最好先查索引,再根据索引定位的结果去找数据索引在MySQL中也叫做“键”或者"key"(primary key,unique key,还有一个index key),是存储引擎用于快速找到记录的一种数据结构。索引对于良好的性能非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发重要,减少io次数,加速查询。(其中primary key和unique key,除了有加速查询的效果之外,还有约束的效果,primary key 不为空且唯一,unique key 唯一,而index key只有加速查询的效果,没有约束效果)
    索引优化应该是对查询性能优化最有效的手段了。索引能够轻易将查询性能提高好几个数量级。
    索引相当于字典的音序表,如果要查某个字,如果不使用音序表,则需要从几百页中逐页去查。

    强调:一旦为表创建了索引,以后的查询最好先查索引,再根据索引定位的结果去找数据

2.前提

尽量使用唯一性比较好的条件进行创建索引。(比如主键列)

但凡创建主键列,会自动创建一个主键索引,一旦指定主键列生成主键索引之后,将来使用此列作为条件进行查询的时候,就有可能使用索引查询。(走索引)

3.索引的优缺点

创建索引可以大大提高系统的性能。

  • 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
  • 可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
  • 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
  • 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
  • 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

缺点:

1、在表中有大量数据的前提下,创建索引速度会很慢

2、在索引创建完毕后,对表的查询性能会发幅度提升,但是写性能会降低

4.创建索引的原则

数据库索引的设计原则:

为了使索引的使用效率更高,在创建索引时,必须考虑在哪些字段上创建索引和创建什么类型的索引。

那么索引设计原则又是怎样的?

1.选择唯一性索引

唯一性索引的值是唯一的,可以更快速的通过该索引来确定某条记录。

例如,学生表中学号是具有唯一性的字段。为该字段建立唯一性索引可以很快的确定某个学生的信息。

如果使用姓名的话,可能存在同名现象,从而降低查询速度。

2.为经常需要排序、分组和联合操作的字段建立索引

经常需要ORDER BY、GROUP BY、DISTINCT和UNION等操作的字段,排序操作会浪费很多时间。

如果为其建立索引,可以有效地避免排序操作。

3.为常作为查询条件的字段建立索引

如果某个字段经常用来做查询条件,那么该字段的查询速度会影响整个表的查询速度。因此,

为这样的字段建立索引,可以提高整个表的查询速度。

4.限制索引的数目

索引的数目不是越多越好。每个索引都需要占用磁盘空间,索引越多,需要的磁盘空间就越大。

修改表时,对索引的重构和更新很麻烦。越多的索引,会使更新表变得很浪费时间。

5.尽量使用数据量少的索引

如果索引的值很长,那么查询的速度会受到影响。例如,对一个CHAR(100)类型的字段进行全文

检索需要的时间肯定要比对CHAR(10)类型的字段需要的时间要多。

6.尽量使用前缀来索引

如果索引字段的值很长,最好使用值的前缀来索引。例如,TEXT和BLOG类型的字段,进行全文检索

会很浪费时间。如果只检索字段的前面的若干个字符,这样可以提高检索速度。

7.删除不再使用或者很少使用的索引

表中的数据被大量更新,或者数据的使用方式被改变后,原有的一些索引可能不再需要。数据库管理

员应当定期找出这些索引,将它们删除,从而减少索引对更新操作的影响。

8.小表不应建立索引

包含大量的列并且不需要搜索非空值的时候可以考虑不建索引

索引是建立在数据库表中的某些列的上面。在创建索引的时候,应该考虑在哪些列上可以创建索引,在哪些列上不能创建索引。一般来说,应该在这些列上创建索引:

在经常需要搜索的列上,可以加快搜索的速度;

  • 在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
  • 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
  • 在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
  • 在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。

同样,对于有些列不应该创建索引。一般来说,不应该创建索引的的这些列具有下列特点:

  • 对于那些在查询中很少使用或者参考的列不应该创建索引。这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
  • 对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
  • 对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。
  • 当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。

5.不走索引的原因

走不走索引的决定权在优化器上

(1)集群因子过大,可能不走索引

(2)将来结果集的条目占总数据量的30%的时候,优化器就觉得走全扫描计划更好(where)

(3)默认的order by 单独使用的时候。优化也觉得全表的方式更好(where和limit)

(4)子查询尽量避免 union 或者 union all

(5)select 使用了不合理的条件或功能(没有where 逻辑计算符 函数类似于 sum())

(6)带有select * 可能不走索引

(7)where条件中有like 并且‘%a%’,可以支持'a%'(超过30%还是不走索引 )

6.b-树,,b+树

B-树的特性:

  • 关键字集合分布在整颗树中;
  • 任何一个关键字出现且只出现在一个结点中;
  • 搜索有可能在非叶子结点结束;
  • 其搜索性能等价于在关键字全集内做一次二分查找;
  • 自动层次控制;

b+树的特性

  • 有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好
  • 是有序的;
  • 不可能在非叶子结点命中;
  • 非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储
  • (关键字)数据的数据层;
  • 更适合文件索引系统;

7.聚集索引与辅助索引

InnoDB存储引擎表示索引组织表,即表中数据按照主键顺序存放。而聚集索引(clustered index)就是按照每张表的主键构造一棵B+树,同时叶子结点存放的即为整张表的行记录数据,也将聚集索引的叶子结点称为数据页。聚集索引的这个特性决定了索引组织表中数据也是索引的一部分。同B+树数据结构一样,每个数据页都通过一个双向链表来进行链接。
    
如果未定义主键,MySQL取第一个唯一索引(unique)而且只含非空列(NOT NULL)作为主键,InnoDB使用它作为聚簇索引。
    
如果没有这样的列,InnoDB就自己产生一个这样的ID值,它有六个字节,而且是隐藏的,使其作为聚簇索引。

由于实际的数据页只能按照一棵B+树进行排序,因此每张表只能拥有一个聚集索引。在多少情况下,查询优化器倾向于采用聚集索引。因为聚集索引能够在B+树索引的叶子节点上直接找到数据。此外由于定义了数据的逻辑顺序,聚集索引能够特别快地访问针对范围值得查询。

回表查询:有个表 id , name

通过 select id from 表 where name = "xxx";;

name有普通索引 但是我们要查的是 id ,先查普通索引 ,普通索引记录着 聚集索引的值然后从头开始重新查聚集索引

普通索引INDEX:加速查找

唯一索引:
    -主键索引PRIMARY KEY:加速查找+约束(不为空、不能重复)
    -唯一索引UNIQUE:加速查找+约束(不能重复)

联合索引:
    -PRIMARY KEY(id,name):联合主键索引
    -UNIQUE(id,name):联合唯一索引
    -INDEX(id,name):联合普通索引

添加删除索引

添加主键索引:
创建的时候添加:  添加索引的时候要注意,给字段里面数据大小比较小的字段添加,给字段里面的数据区分度高的字段添加.
聚集索引的添加方式
创建的是添加
Create table t1(
Id int primary key,
)
Create table t1(
Id int,
Primary key(id)
)

表创建完了之后添加
Alter table 表名 add primary key(id)
删除主键索引:
Alter table 表名 drop primary key;


唯一索引:
Create table t1(
Id int unique,
)

Create table t1(
Id int,
Unique key uni_name (id)
)

表创建好之后添加唯一索引:
alter table s1 add unique key  u_name(id);
删除:
Alter table s1 drop index u_name;

普通索引:
创建:
Create table t1(
Id int,
Index index_name(id)
)
Alter table s1 add index index_name(id);
#Create index index_name on s1(id);

删除:
Alter table s1 drop index u_name;
#DROP INDEX 索引名 ON 表名字;

8.索引的两大类型hash和btree

#我们可以在创建上述索引的时候,为其指定索引类型,分两类
hash类型的索引:查询单条快,范围查询慢
btree类型的索引:b+树,层数越多,数据量指数级增长(我们就用它,因为innodb默认支持它)

#不同的存储引擎支持的索引类型也不一样
InnoDB 支持事务,支持行级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
MyISAM 不支持事务,支持表级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
Memory 不支持事务,支持表级别锁定,支持 B-tree、Hash 等索引,不支持 Full-text 索引;
NDB 支持事务,支持行级别锁定,支持 Hash 索引,不支持 B-tree、Full-text 等索引;
Archive 不支持事务,支持表级别锁定,不支持 B-tree、Hash、Full-text 等索引;

9.查询优化神器-explain

explain  select * from s1 where id = "111111";
#rows 显示的是查询了多少行 key是走没有索引

14.事务

    事务是由一组SQL语句组成的逻辑处理单元,事务中要么全部成功,要不全部失败
    原子性(Atomicity):事务是一个原子操作单元。在当时原子是不可分割的最小元素,其对数据的修改,要么全部成功,要么全部都不成功。
    一致性(Consistent):事务开始到结束的时间段内,数据都必须保持一致状态。
    隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的"独立"环境执行。
    持久性(Durable):事务完成后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。

15.sql优化

1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。    
    
2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:    
select id from t where num is null    
可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:    
select id from t where num=0    
    
3.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。    
    
4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:    
select id from t where num=10 or num=20    
可以这样查询:    
select id from t where num=10    
union all    
select id from t where num=20    
    
5.in 和 not in 也要慎用,否则会导致全表扫描,如:    
select id from t where num in(1,2,3)    
对于连续的数值,能用 between 就不要用 in 了:    
select id from t where num between 1 and 3    
    
6.下面的查询也将导致全表扫描:    
select id from t where name like '%abc%'    
    
7.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:    
select id from t where num/2=100    
应改为:    
select id from t where num=100*2    
    
8.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:    
select id from t where substring(name,1,3)='abc'--name以abc开头的id    
应改为:    
select id from t where name like 'abc%'    
    
9.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。    
    
10.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,    
否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。    
    
11.不要写一些没有意义的查询,如需要生成一个空表结构:    
select col1,col2 into #t from t where 1=0    
这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:    
create table #t(...)    
    
12.很多时候用 exists 代替 in 是一个好的选择:    
select num from a where num in(select num from b)    
用下面的语句替换:    
select num from a where exists(select 1 from b where num=a.num)    
    
13.并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,    
如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。    
    
14.索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,    
因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。    
一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。    
    
15.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。    
这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。    
    
16.尽可能的使用 varchar 代替 char ,因为首先变长字段存储空间小,可以节省存储空间,    
其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。    
    
17.任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。    
    
18.避免频繁创建和删除临时表,以减少系统表资源的消耗。

19.临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。    
    
20.在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,    
以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。

21.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。    
    
22.尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。    
    
23.使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。

24.与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。
在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。

25.尽量避免大事务操作,提高系统并发能力。

26.尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。
原文地址:https://www.cnblogs.com/zdqc/p/11460867.html