mysql整理笔记

  • 2021-12-22
  • Admin

mysql安装:

安装:

wget https://cdn.mysql.com//Downloads/MySQL-8.0/mysql-8.0.15-1.el7.aarch64.rpm-bundle.tar
sudo rpm -Uvh mysql80-community-release-el7-2.noarch.rpm
yum install  -y  mysql-community-server        # 安装mysql服务端
sudo service mysqld start    相当于centos7的systemctl start mysqld.service # restart
service mysqld status        查看是否启动成功或失败原因,systemctl status mysql.service,启动失败可以看error log有输出

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

ubuntu下:

sudo apt-get install mysql-server
sudo apt install mysql-client
sudo apt install libmysqlclient-dev

  • 1
  • 2
  • 3
  • 4

配置文件路径:

/etc/my.cnf
/etc/mysql/my.cnf
/var/lib/mysql/my.cnf

  • 1
  • 2
  • 3
  • 4

启动mysql服务与停止mysql服务命令:

sudo service mysqld start    service mysqld restart (rpm安装)

  • 1
  • 2

登陆与退出命令:

mysql -h 服务器IP -P 端口号 -u  用户名 -p 密码 --prompt 命令提示符  --delimiter 指定分隔符
mysql -h 127.0.0.1 -P 3306 -u root -p 

  • 1
  • 2
  • 3

常见安装以及操作问题:

1.关于root用户默认不能远程登录的问题:

默认本地不能通过内网或者127.0.0.1都可以登录的
    skip-name-resolve
配置环境变量:
    MYSQL_ROOT_HOST=%

  • 1
  • 2
  • 3
  • 4
  • 5

2.shell无法输入中文:

容器启动需要-e LANG=C.UTF-8
docker run -d -it -e MYSQL_ROOT_PASSWORD=123 --name mysql2 -e LANG=C.UTF-8 -p 3306:3306  mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

  • 1
  • 2
  • 3

3.NFS上mysql启动不了的问题:

dmesg提示lock server等待
mount -o nolock才行

  • 1
  • 2
  • 3

用户管理:

修改密码:

注意:

mysql5.7.6版本后 废弃user表中 password字段 和 password()方法,所以旧方法重置密码对mysql8.0版本是行不通的

  • 1
  • 2

方法一(配置):

vim /etc/my.cnf
    在【mysqld】模块添加:skip-grant-tables
service mysqld restart        # 重启配置,然后免密码登陆,use mysql,清空密码,更新配置重启,登陆,设置新密码:
ALTER USER 'root'@'%' IDENTIFIED BY 'root123';

  • 1
  • 2
  • 3
  • 4
  • 5

方法二(第一次登陆):

grep 'temporary password' /var/log/mysqld.log    找到临时密码
登陆
ALTER USER 'root'@'localhost' IDENTIFIED BY 'root123';

  • 1
  • 2
  • 3
  • 4

方式三(5.x版本):

update user set Host="%" where User="root";          # 可以改Host       

  • 1
  • 2

方式四(8.x版本):

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'corona@2020@wuhan';
grant all privileges on *.* to 'root'@'localhost' with grant option;  这个方法只能修改权限,不能改Host
FLUSH PRIVILEGES;

  • 1
  • 2
  • 3
  • 4

忘记密码:

方式一:

vi /etc/my.cnf 在[mysqld]的段中加上一句:skip-grant-tables 保存并且退出vi。
service mysqld restart
mysql -uroot
USE mysql;    UPDATE user SET Password = password ( 'new-password' ) WHERE User = 'root' ; 
    update mysql.user set authentication_string=password('123456a') where user='root';
还原my.cnf配置
service mysqld restart

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

方式二:

直接停了再额外参数启动,mysqld --skip-grant-tables &

  • 1
  • 2

指定账号语法:

1.语法是'user_name'@'host_name'。
2.只指定username时,等价于'user_name'@'%'。
3.如果username和hostname未加引号时合法,可以不加引号,不合法如用户名包含-,空格,hostname包含. % 。
4.引号可以使用单引号、双引号、反引号。
5.当前账号可以用 CURRENT_USER 或 CURRENT_USER()。
6.host字段可以使用%和_(匹配任意一个字符),类似like中的用法。
    注:172.31.% 在Mysql中不会匹配172.31.example.com这类以数字和点开头的域名。
7. IPv4可以使用netmask,如CREATE USER 'david'@'198.51.100.0/255.255.255.0'即198.51.100开头的0-255范围的ip。
8.客户端的host name或ip会先被系统的dns解析后返回给mysql,用来匹配对应账号的host字段,所以本地dns返回的格式很重要如198.051.100就不规范。
关于mysql数据库:
    user表每个账号有一行数据,User和Host列,以及账号的权限
    其他表存放账号对数据库和表的权限,也有User和Host列,对应着user表的值
    User字段是大小写区分的,Host字段不区分大小写

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

修改远程访问ip:

方法一:

use mysql
select host,user,authentication_string,plugin from user;
update user set host = "%" where user = "root";            # 更新host的时候不会保留原来的权限
FLUSH PRIVILEGES;
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'WITH GRANT OPTION;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

方法二:

RENAME USER 'test'@'172.%' TO 'test'@'%';   保留原来的权限

  • 1
  • 2

查看连接ip信息:

select SUBSTRING_INDEX(host,':',1) as ip , count(*) from information_schema.processlist group by ip;

  • 1
  • 2

创建用户:

示例:

CREATE USER 'czl'@'172.31.%' IDENTIFIED BY 'Czl1234.';
CREATE USER 'test'@'%' IDENTIFIED WITH mysql_native_password BY 'Czl1234.';
grant all privileges on *.* to 'czl'@'172.31.%';            # 需要grant权限,查user表可看,注意name和domain必须一致
                                                        # 8.0之前版本可以通过这个命令创建新的用户+domain

  • 1
  • 2
  • 3
  • 4
  • 5

如何匹配多个网段:

1.update mysql.user set Host=“172.%” where User=‘czl’; # domain是表的一个columns,只能update,不能grant更新
2.再创建一个不同domain相同name的用户:
mysql会根据domain和username来匹配用户,domain和username是联合主键,Duplicate entry '172.%-test' for key 'PRIMARY'(旧版本也这样)
mysql会优先匹配出domain匹配度高的那一条数据,如172.%比%优先,然后使用那条数据的密码和权限配置
旧版本也是根据username+domain来做联合主键,只是grant能否创建新账号的区别

  • 1
  • 2
  • 3
  • 4

旧版本创建方式:

CREATE USER 'grafana'@'%' IDENTIFIED WITH mysql_native_password BY 'Grafana1234.';(这个不变)
或grant all privileges on *.* to 'czl'@'172.31.%';

  • 1
  • 2
  • 3

修改权限:

grant select on *.* to 'czl'@'172.31.%';        # 如果已有该权限,不变,如果没有就更新。范围变化也会更新(范围存放其他表)
                                                # 需要注意username和domain要一致

  • 1
  • 2
  • 3

删除用户:

方法一:

delete from user where user="czl";
FLUSH PRIVILEGES;

  • 1
  • 2
  • 3

方法二:

Drop user 'test'@'%';            # 'test'等价于'test'@'%'

  • 1
  • 2

撤销权限:

revoke super on *.* from 'czl'@localhost;        # from

  • 1
  • 2

设置只读:

show global variables like "%read_only%";
set global read_only=1;             # 对拥有super权限的账号是不生效的

  • 1
  • 2
  • 3

常见规范:

1. 在数据库系统中,SQL语句不区分大小写(建议用大写) 。但字符串常量区分大小写。建议命令大写,表名库名小写。
2. SQL语句可单行或多行书写,以“;”结尾。关键词不能跨多行或简写。
3. 用空格和缩进来提高语句的可读性。子句通常位于独立行,便于编辑,提高可读性。
4. 注释:单行注释:-- 多行注释:/*......*/(js)
5. 命名和内置关键词冲突时,使用``引号。
6. DML、DDL、DCL区别
    DML(data manipulation language):用来对数据库里的数据进行操作的语言
    DDL(data definition language):主要是用在定义或改变表(TABLE)的结构,数据类型,表之间的链接和约束等
                                    初始化工作上,他们大多在建立表时使用
    DCL(Data Control Language):是数据库控制功能。是用来设置或更改数据库用户或角色权限的语句
7. 三大范式:
    1NF:字段不可分;
    2NF:有主键,非主键字段依赖主键;
    3NF:非主键字段不能相互依赖;

    数据库反三范式
        反范式化指的是通过增加冗余或重复的数据来提高数据库的读性能
        使用场景
            当需要查询“订单表”所有数据并且只需要“用户表”的name字段时, 没有冗余字段 就需要去join 连接用户表,假设表中数据量非常的大, 那么会这次连接查询就会非常大的消耗系统的性能. 这时候冗余的字段就可以派上用场了, 有冗余字段我们查一张表就可以了.

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

数据类型:

1.数字

TINYINT            --小整数,特别的: MySQL中无布尔值,使用tinyint(1)构造。
SMALLINT
MEDIUMINT
INT\INTEGER        --整数类型中的m仅用于显示,对存储范围无限制。int(5),当插入数据2时,select 时数据显示为: 00002。8.0之前会存在主键回溯问题(8.0后持久化主键,delete不影响)达到上限后会报主键重复。
BIGINT            -- 推荐主键类型。
FLOAT(m,d)            --单精度浮点数(非准确小数值),m是数字总个数,d是小数点后个数。
DOUBLE(m,d)            --数值越大,越不准确
DECIMAL(m,d)        --对于精确数值计算时需要用此类型,参数m<65 是总个数,d<30且 d
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2.日期/时间

DATE        YYYY-MM-DD
TIME        HH-MM-SS
YEAR        
DATETIME    YYYY-MM-DD HH-MM-SS,Datetime(n)n表示毫秒的精度,固定8个字节。推荐,不存在时区转换问题
TIMESTAMP    YYYYMMDD HHMMSS存储1971年到现在的毫秒数(7字节),最大的优点是带有时区属性。需要从毫秒数转换,存在性能问题

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3.字符串

CHAR            --定长,0-255字符长度,规定字符长度n,拿取效率高,即使数据小于m长度,也会占用m长度,查询性能更好。存储按照指定长度,检索时去掉尾随空格。
VARCHAR            # 变长,只取需要长度。更新可能会导致碎片问题(原位置不满足长度)。注意在utf8mb4字符格式下,固定用4个字节。
TINYBLOB
TINYTEXT
BLOB            # 二进制
TEXT            # 长文本
MEDIUMBLOG
MEDIUMTEXT
LONGBLOB
LONGTEXT    
JSON    5.7出现,8.0解决存储性能问题。提供很多读取操作,比较方便。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

4.枚举类型

enum            --size ENUM('x-small', 'small', 'medium', 'large', 'x-large')   

  • 1
  • 2

5.集合类型

set                --SET('a', 'b', 'c', 'd')

  • 1
  • 2

JSON:

概述:

与text的区别:多了在数据库操作原生字典的方法

  • 1
  • 2

创建:

JSON NOT NULL,

  • 1
  • 2

插入:

INSERT INTO t_json(id,sname,info) VALUES( 1, 'name1', JSON_ARRAY(1, "abc", NULL, TRUE, CURTIME()));
INSERT INTO t_json(id,sname,info) VALUES( 2, 'name2', JSON_OBJECT("age", 20, "time", now()));
INSERT INTO t_json(id,sname,info) VALUES( 3, 'name3', '{"age":20, "time":"2018-07-14 10:52:00"}');    
SELECT JSON_MERGE_PRESERVE('["a", 1]', '{"key": "value"}');
SELECT JSON_QUOTE('[1,2,3]');

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

操作:

判断类型:
SELECT JSON_TYPE('["a", "b", 1]');
SELECT JSON_TYPE('"hello"');

  • 1
  • 2
  • 3
是否有效:
SELECT JSON_VALID('null'), JSON_VALID('Null'), JSON_VALID('NULL');    # 敏感,而sql内置对于大小写不敏感

SELECT CAST('null' AS JSON);

  • 1
  • 2
  • 3
  • 4
查找指定数据:
JSON_EXTRACT(json_doc, path[, path] ...)从json文档里抽取数据。如果有参数有NULL或path不存在,则返回NULL。如果抽取出多个path,则返回的数据封闭在一个json array里。
SELECT JSON_EXTRACT('{"id": 14, "name": "Aztalan"}', '$.name');
SELECT JSON_EXTRACT('{"a": 1, "b": 2, "c": [3, 4, 5]}', '$.*');        
SELECT JSON_EXTRACT('{"a": 1, "b": 2, "c": [3, 4, 5]}', '$.c[*]');    # 获取key为c的所有内容
SELECT JSON_EXTRACT('{"a": {"b": 1}, "c": {"b": 2}}', '$**.b');        # $**获取所有的key的b对应value
SELECT JSON_EXTRACT('[1, 2, 3, 4, 5]', '$[1 to 3]');            # list操作
SELECT JSON_EXTRACT('[1, 2, 3, 4, 5]', '$[last-3 to last-1]');    
SELECT JSON_REPLACE('"Sakila"', '$[last]', 10);                    # 注意不是数组时替换整个

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
设置:
SELECT JSON_SET('"x"', '$[0]', 'a','$[1]', 'b');    # 已存在会覆盖

  • 1
  • 2
新增:
SELECT JSON_INSERT(@j, '$[1].b[0]', 1, '$[2][2]', 2);

  • 1
  • 2
替换:
SELECT JSON_REPLACE(@j, '$[1].b[0]', 1, '$[2][2]', 2);

  • 1
  • 2
删除:
SELECT JSON_REMOVE(@j, '$[2]', '$[1].b[1]', '$[1].b[1]');

指定数据是否存在
JSON_CONTAINS(json_doc, val[, path])# 查询json文档是否在指定path包含指定的数据,包含则返回1,否则返回0。如果有参数为NULL或path不存在,则返回NULL。
SELECT JSON_CONTAINS(@j, '4', '$.c.d');    

指定路径是否存在
JSON_CONTAINS_PATH(json_doc, one_or_all, path[, path] ...)# 查询是否存在指定路径,存在则返回1,否则返回0。如果有参数为NULL,则返回NULL。
    set @j = '{"a": 1, "b": 2, "c": {"d": 4}}';
    SELECT JSON_CONTAINS_PATH(@j, 'one', '$.a', '$.e'); -- 1
    SELECT JSON_CONTAINS_PATH(@j, 'all', '$.a', '$.c.d'); -- 1    

查找所有指定键值
JSON_KEYS(json_doc[, path])  获取json文档在指定路径下的所有键值,返回一个json array。如果有参数为NULL或path不存在,则返回NULL。
    SELECT JSON_KEYS('{"a": 1, "b": {"c": 30}}'); -- ["a", "b"]
    SELECT JSON_KEYS('{"a": 1, "b": {"c": 30}}', '$.b'); -- ["c"]      

查找指定值(key or value)的位置
JSON_SEARCH(json_doc, one_or_all, search_str[, escape_char[, path] ...])
# 查询包含指定字符串的paths,并作为一个json array返回。如果有参数为NUL或path不存在,则返回NULL。
# one_or_all:"one"表示查询到一个即返回;"all"表示查询所有。
# search_str:要查询的字符串。 可以用LIKE里的'%'或‘_’匹配。
示例:
    SET @j3 = '["abc", [{"k": "10"}, "def"], {"x":"abc"}, {"y":"bcd"}]';
    SELECT JSON_SEARCH(@j3, 'one', 'abc'); -- "$[0]"
    SELECT JSON_SEARCH(@j3, 'all', 'abc'); -- ["$[0]", "$[2].x"]
    SELECT JSON_SEARCH(@j3, 'all', 'abc', NULL, '$[2]'); -- "$[2].x"
    SELECT JSON_SEARCH(@j3, 'all', '10'); -- "$[1][0].k"
    SELECT JSON_SEARCH(@j3, 'all', '%b%'); -- ["$[0]", "$[2].x", "$[3].y"]
    SELECT JSON_SEARCH(@j3, 'all', '%b%', NULL, '$[2]'); -- "$[2].x"

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

字符集:

char和varchar的影响:

8.0之后默认为utf8mb4(一个字符最多4个字节),之前的utf8,会存在插入表情字符异常问题(utf8范围不够)。
对于单一字符比如a,varchar存储2个字节(一个用来存长度),char存储1个字节
对于不同字符,比如a和"我",char(4)分别存储1+3个字节和3+3个字节。
结论:对于字符类型不固定的字段,用varchar和char都会产生硬盘碎片化。文件都是按照字节byte来读取的。

  • 1
  • 2
  • 3
  • 4
  • 5

设置:

character-set-server=utf8mb4

  • 1
  • 2

修改表字符集:

alter table xxx convert to character utf8mb4

  • 1
  • 2

DDL操作:

1.创建数据库

create database [if not exists] db_name [character set xxx] 
CREATE DATABASE IF NOT EXISTS my_db default charset utf8 COLLATE utf8_general_ci;

  • 1
  • 2
  • 3

2.查看数据库

show databases;查看所有数据库
show create database db_name; 查看数据库的创建方式
自带数据库:
    information_schema: 信息数据库,记录其他数据库的信息
    sys: dba运维需要,一些慢查询sql的记录
    performance_schema: 性能

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

3.修改数据库

alter database db_name [character set xxx]

  • 1
  • 2

4.删除数据库

drop database [if exists] db_name;

  • 1
  • 2

5.使用数据库

切换数据库 use db_name; -- 注意:进入到某个数据库后没办法再退回之前状态,但可以通过use进行切换
查看当前使用的数据库 select database();

  • 1
  • 2
  • 3

6.创建表

create table tab_name(
            field1 type[完整性约束条件],
            field2 type,
            ...
            fieldn type
    KEY `id` (`id`)             # 圆括号内的id是字段名称,圆括号左侧外面的id是索引名称。
        )[character set xxx][ENGINE=innodb\mysaim];    # innodb支持事务、行锁、表锁;mysaim支持表锁
索引约束:
    primary key (非空且唯一)  :能够唯一区分出当前记录的字段称为主键!
    unique
    not null
    auto_increment 主键字段必须是数字类型。
外键约束:
    foreign key  */
其他方式:
    create table aa(select * from bb)   --把数据都复制过来,而外键那些不复制
复制表结构:
    create table a like b
部分克隆:
    CREATE TABLE A AS SELECT x,x,x,xx FROM B LIMIT 0

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

7.查看表信息:

desc tab_name 查看表结构
show columns from tab_name  查看表结构    --效果一样
show tables 查看当前数据库中的所有的表
show create table tab_name    查看当前数据库表建表语句 

  • 1
  • 2
  • 3
  • 4
  • 5

8.修改表结构:

(1)增加列(字段)
    alter table tab_name add [column] 列名 类型[完整性约束条件][first|after 字段名];
    alter table users2 
        add addr varchar(20),
        add age  int first,
        add birth varchar(20) after name;
(2)修改一列类型
    alter table tab_name modify 列名 新类型 [完整性约束条件][first|after 字段名];
(3)修改列名(可修改类型)
    alter table tab_name change [column] 列名 新列名 类型 [完整性约束条件][first|after 字段名];
(4)删除一列
    alter table tab_name drop [column] 列名; 
(5)修改表名
    rename table 表名 to 新表名;
(6)修该表所用的字符集    
    alter table student character set utf8;
(7)修改索引主键
    先删除再添加
    alter table featuredatadb.r_cash_loan_old_user_model_result drop primary key;
    alter table featuredatadb.r_cash_loan_old_user_model_result add primary key (`uid`,`cash_loan_id`,`model_version`);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

9.删除表

drop table tab_name;

  • 1
  • 2

10.修改默认值:ALTER TABLE testalter_tbl ALTER i SET DEFAULT 1000;

删除默认值:ALTER TABLE testalter_tbl ALTER i DROP DEFAULT;

  • 1
  • 2

DML操作:

INSERT:

语法:

insert [into] tab_name (field1,filed2,.......) values (value1,value2,.......);

  • 1
  • 2

插入多条数据(不带字段时默认全部字段):

insert into employee_new values (4,'alvin1','1993-04-20',3000),(5,'alvin2','1995-05-12',5000);

  • 1
  • 2

set插入:

insert [into] tab_name set 字段名=值
insert into employee_new set id=12,name="alvin3";

  • 1
  • 2
  • 3

ON DUPLICATE KEY UPDATE的使用:

ON DUPLICATE KEY UPDATE c=VALUES(a)+b
1. 列名b表示原数据库的旧值,VALUES(b)表示引用被新插入的col_name的值
2. 可以使用if语法
    on duplicate key update update_time=if(update_time>values(update_time),update_time,values(update_time))
3. 可以使用case when语法
     on duplicate key update created_at=case when created_at=values(created_at) then created_at end
        # 可以使用其他字段名称
    # on duplicate key update level=values(level), update_time=case when level<>values(level) then values(update_time) else update_time end
    # 这种写法,先更新了level,那么后面的语法查到的level与values(level)都是update后的同一个level
4. update level=values(level)如果新旧值不一样,才会去更新,才触发触发器
   需要注意一下多个update值是否都更新了,如update_time
5. 需要避免的使用情况
    a. 最好values括号内不要加新括号,否则如果values后面任意的一个()内再有)的话,会一直匹配到该处的)
    b. 如要添加,确保后面的一个()没有子括号

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

UPDATE:

update tab_name set field1=value1,field2=value2,......[where 语句]

  • 1
  • 2

DELETE:

delete from tab_name [where ....]

  • 1
  • 2

SELECT:

查询表达式:

    SELECT *|field1,filed2 ...   FROM tab_name
        WHERE 条件
        GROUP BY field
        HAVING 筛选
        ORDER BY field
        LIMIT 限制条数
        OFFSET 
        UNION 去重组合      # UNION ALL 不管重复,上下并接

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

原文:https://blog.csdn.net/weixin_39890410/article/details/122083031

联系站长

QQ:769220720