mysql笔记

安装

ubutun的MySQL安装

shell 复制代码
# 更新软件包列表并升级已安装的软件包
sudo apt update && sudo apt upgrade
# 清理系统中已删除软件包的残留配置文件
dpkg -l |grep ^rc|awk '{print $2}' |sudo xargs dpkg -P
# 安装 MySQL 服务器
sudo apt install  mysql-server
# 以 root 用户身份登录 MySQL
mysql -uroot -p

windows安装

  1. 网站:dev.mysql.com/downloads/m...
  2. 你需要下载压缩包版本,解压后放到你想放的位置,进入解压后的文件夹建立mysql.ini文件。文件输入以下内容:
shell 复制代码
[mysqld]
# 设置MySQL安装目录(替换为你的解压路径)
basedir=D:\Users\wnan\AppData\Local\mysql-8.0.44-winx64
# 设置MySQL数据存储目录(自动生成,无需手动创建)
datadir=D:\Users\wnan\AppData\Local\mysql-8.0.44-winx64\data
# 设置端口号(默认3306,若被占用可修改为3307等)
port=3306
# 设置字符集(默认UTF-8,支持中文)
character-set-server=utf8mb4
# 设置默认存储引擎
default-storage-engine=INNODB
# 允许最大连接数
max_connections=100

[mysql]
# MySQL客户端字符集
default-character-set=utf8mb4

[client]
# 客户端连接端口
port=3306
# 客户端字符集
default-character-set=utf8mb4
  1. 设置环境变量:D:\Users\wnan\AppData\Local\mysql-8.0.44-winx64\bin
  2. 打开poershell,这里需要管理员权限的方式打开。执行指令:
shell 复制代码
# 初始化
mysqld --initialize --console
# 窗口会输出一串日志,找到 root@localhost: 后面的字符串(例如:root@localhost:abcd1234!),这是 临时密码,复制保存(后续登录需要);

# 注册安装MySQL服务
mysqld -install
# 输出:Service successfully installed. 就表示成功

用户管理

用户建立、授权、收权、删除

  1. 建立用户
sql 复制代码
-- 建立用户 
create user '[用户的名字]'@'[设备的IP地址]' identified by '[用户的登录密码]';
-- 查看权限
show grants for '[用户的名字]'@'[设备的IP地址]';

设备的IP地址:%表示任意IP均可以登录;localhost表示本地登录。

  1. 授权
sql 复制代码
-- 授予所有权限
grant all privileges on testDB.* to '[用户的名字]'@'[设备的IP地址]' identified by '[用户的登录密码]';
-- 查看权限
show grants for '[用户的名字]'@'[设备的IP地址]';
-- 刷新系统
flush privileges;

grant语句中,testDB.*指的是数据库testDB中的所有表。这里的星号(*)作为一个通配符,代表数据库中的所有表。具体来说:testDB是数据库的名称。.是点操作符,用于指定数据库层级。*代表所有表。因此,当您看到grant语句中的on testDB.* to时,它意味着授予用户对testDB数据库中所有表的指定权限。这是一种简洁的方式来一次性授予对多个表的操作权限,而不是单独为每个表列出权限。

可能错误

sql 复制代码
mysql> revoke all  on bbs.* from 'admin1'@'localhost';
ERROR 1044 (42000): Access denied for user 'root'@'%' to database 'bbs'
-- 1044提示root访问bbs库被拒绝  
mysql> grant all privileges on bbs.* to 'root'@'%';
ERROR 1044 (42000): Access denied for user 'root'@'%' to database 'bbs'
      
mysql> grant all  on *.* to 'root'@'%';
ERROR 1045 (28000): Access denied for user 'root'@'%' (using password: YES)
-- 1045提示root访问被拒绝
sql 复制代码
-- 查看用户权限
select user,host from mysql.user;
select host,user,Grant_priv,Super_priv from mysql.user;

可以看到Grant_priv是N。很显然,因为root@'%'这个用户没有授予权限的权限,所以之前的操作报错。修改一下Grant_priv的值为Y,刷新下,然后退出重新登录。问题就解决了。

sql 复制代码
update mysql.user set Grant_priv='Y' where user='root';
flush privileges;
  1. 移除权限
sql 复制代码
-- 移除全部权限
revoke all privileges on *.* from '[用户的名字]'@'[设备的IP地址]';
flush privileges;
  1. 删除用户
sql 复制代码
use mysql;
drop user '[用户的名字]'@'[设备的IP地址]';

远程登录

  • MySQL8及以上版本
sql 复制代码
-- 创建'root'@'%'账户
create user 'root'@'%' identified by '[用户登录密码]';
-- 给'root'@'%'账户设置权限
grant all privileges on *.* to 'root'@'%';
-- 刷新权限
flush privileges;
-- 查看root
use mysql;
select host, user, authentication_string, plugin from user;

应该可以看到有两个root账户,一个是'root'@'localhost'和'root'@'%'。看一下两个账号的加密插件是不是caching_sha2_password,为什么要看呢?具体原因往下看。 这次应该可以正常连接了。如果连接的时候显示plugin caching_sha2_password could not be loaded,那我们就需要改一下加密插件了。 方法一: 这种方法应当在创建'root'@'%'之前设置,不然就使用第二种更加方便。 可以理解为,方法一是为之后所有新用户指定加密插件。 方法二是修改指定一个用户的加密插件。

修改my.ini文件。

shell 复制代码
[mysqld]
default_authentication_plugin=mysql_native_password

方法二:

sql 复制代码
alter user 'root'@'%' identified with mysql_native_password by '123456'

服务器没有开放端口

shell 复制代码
netstat -an | grep 3306
# 如果没有如下信息,则不是任意IP可访问
tcp6       0      0 :::3306                 :::*                    LISTEN  

vim /etc/mysql/mysql.conf.d/mysqld.cnf
# 修改,注释 bind-address  = 127.0.0.1
# ---------------以下是文件截图----------------
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
# bind-address          = 127.0.0.1
mysqlx-bind-address     = 127.0.0.1
# -------------------------------------------

# 重启mysql
/etc/init.d/mysql restart

数据库操作

建立数据库

sql 复制代码
create database if not exists [数据库名称];
-- 设置字符集和排序规则【建立数据库时】
create database if not exists [数据库名称] character set 'utf8mb4' collate utf8mb4_unicode_ci;
-- 设置字符集和排序规则【建立数据库后修改】
alter database [数据库名称] character set 'utf8mb4' collate utf8mb4_unicode_ci;

utf8mb4:平时的utf8字符集。
utf8mb4_unicode_ci:不区分大小写排序规则。

删除数据库

sql 复制代码
drop database if exists [数据库名称];

查看数据库是否存在

sql 复制代码
select schema_name 
from information_schema.schemata 
where schema_name='[数据库名称]';

表操作

建立表

sql 复制代码
create table if not exists 表名( 
	列名1 数据类型 [约束条件], 
	列名2 数据类型 [约束条件],
	... [表级约束] 
) [表选项];
约束条件 解释
default null 默认字段为空
not null 字段非空
comment '对字段的标记注释' 对字段的标记注释
unique 确保修饰列的所有值是唯一的
auto_increment 设置字段自增
表级约束 解释
primary key(主键字段名称1,主键字段名称2,...) 设置表的主键
constraint 外键约束名称 foreign key (当前表的字段名1,当前表的字段名2,...) references 被参照的外表名称(外表的字段名称1,外表的字段名称2,...) 设置外键参照
index 索引名称(表字段名称1,表字段名称2,...) 复合索引
unique index 唯一索引名称(表字段名称1,表字段名称2,...) 唯一索引
表选项 解释
engine=InnoDB 设置存储引擎
default charset= 字符集
collate= 排序规则

建立临时表

sql 复制代码
create temporary table 临时表名(
	列名1 数据类型 , 
	列名2 数据类型 ,
    ...
);

-- 或
create temporary table 临时表名 as sql_语句;

删除表

sql 复制代码
drop table 表名称;

修改表名

sql 复制代码
rename table 当前表名字 to 需要改为的表名字;

清空表数据,但是不删除表

sql 复制代码
truncate table 表名字;

表是否存在

sql 复制代码
show tables like '表名字';
-- 模糊查询

级联删除

sql 复制代码
drop table 表名字 cascade;
-- 会删除与表有关联得其他表和数据

添加列名

sql 复制代码
alter table 表名字 add 字段名字 字段类型 remark;

删除列

sql 复制代码
alter table 表名字 drop column 表字段名字;

重命名列

sql 复制代码
alter table 表名字 change 当前表字段名字 新的字段名字;

修改列的数据类型

sql 复制代码
alter table 表名字 modify column 表字段名字 新的字段类型 字段的定义;
-- 如果字段有唯一性约束,可能会无法执行

表约束

添加约束

sql 复制代码
alter table 表名字 add [constraint 约束的名字] 约束的定义;

-- 添加外键约束
alter table 表名字
add constraint 约束的名字
foreign key (表字段的名字1,表字段的名字2,...) references 外部表的名字(外部表的字段名字1,外部表的字段名字2,...);

-- 添加主键约束
alter table 表名 add primary key (表字段的名字);

修改约束

sql 复制代码
-- 先删除约束,再添加约束

删除约束

sql 复制代码
alter table 表名字 drop 约束描述;

表信息

显示表信息

sql 复制代码
desc 表名字;
-- 或
describe 表名字;

查看表列信息

sql 复制代码
show columns from 表名字;
-- 或
select * 
from information_schema.columns
where table_name='表名字' and table_schema='数据库名字';

查看表索引信息

sql 复制代码
show indexes from 表名字;
-- 或
select * 
from information_schema.statistics
where table_name='表名字' and table_schema='数据库名字';

查看表约束信息

sql 复制代码
select * 
from information_schema.table_constraints
where table_name='表名字' and table_schema='数据库名字';

查看表外键约束信息

sql 复制代码
select * 
from information_schema.key_column_usage
where table_name='表名字' and table_schema='数据库名字';

查看建表SQL

sql 复制代码
show create table 表名字;

单元格操作

添加

添加一行数据

sql 复制代码
insert into 表名(表字段名1,表字段名2,...) value ('val1','val2',...);

添加多行数据

sql 复制代码
insert into 表名字(表字段名1,表字段名2,...) values
('val1_0','val2_0',...),
('val1_1','val2_2',...),
('...','...',...);

删除

删除行

sql 复制代码
delete from 表名字 where 字段名字='delete_condition',...;

模糊删除

sql 复制代码
delete from 表名字 where 字段名字 like '%delete_condition%',...;

修改

sql 复制代码
update 表名字
set 字段名字1='new_data1',
set 字段名字1='new_data2',...
where 更新数据的条件;

查询

查询全部数据

sql 复制代码
select * from 表名字;

条件查询

sql 复制代码
select 字段名字1,字段名字2,...
from 表名字
where 字段名字1='select_condition' [and|or] ...;

模糊查询

sql 复制代码
select 字段名字1,字段名字2,...
from 表名字
where 字段名字1 like '%select_condition%' [and|or]...;
  • % 零个或者多个字符
  • _ 单个占位符

排序查询

sql 复制代码
select 字段名字1,字段名字2,...
from 表名字
order by 字段名字1 [asc|desc],字段名字2 [asc|desc],... ;
  • asc:升序
  • desc:降序
  • order by field_name1:这里的field_name1可以设置为数字,数字表示字段的位置顺序

限制返回数查询

sql 复制代码
-- 指定查询数量
select 字段名字1,字段名字2,...
from 表名字
limit number; 
-- number:返回数量

-- 指定查询位置和数量
select 字段名字1,字段名字2,...
from 表名字
limit number offset row_index; 
-- number:返回数量
-- row_index:开始行的索引,

分组查询

sql 复制代码
select 字段名字,count(字段名字)
from 表名字
GROUP BY 字段名字 [WITH rollup];

-- ----------------------- +
2024-01-24	1
2024-02-24	1
2024-10-24	2
2024-11-24	4
2024-11-25	2
null        10 -- [WITH rollup] 上面的总和
-- ------------------------+

union查询

sql 复制代码
-- 会把数据叠成一个表,去掉重复
select 字段名字1,字段名字2,...
from 表名字1;
union [all] -- 有all就是不去掉重复
select 字段名字1,字段名字2,...
from 表名字2;

连接查询:选中指定的列,两个表进行拼接

INNER JOIN(内连接,或等值连接):获取两个表中字段匹配关系的记录。保留两个表都有的数据

LEFT JOIN(左连接):获取左表所有记录,即使右表没有对应匹配的记录。保留左表全部数据

RIGHT JOIN(右连接): 与 LEFT JOIN 相反,用于获取右表所有记录,即使左表没有对应匹配的记录。保留右表全部数据

内连接查询

sql 复制代码
select 字段名字1,...
from 表名字1
inner join 表名字2 on 表名字1.字段名字 = 表名字2.字段名字;

左连接查询

sql 复制代码
select 字段名字1,...
from 表名字1
left join 表名字2 on 表名字1.字段名字 = 表名字2.字段名字;

右连接查询

sql 复制代码
select 字段名字1,...
from 表名字1
right join 表名字2 on 表名字1.字段名字 = 表名字2.字段名字;

比较运算符

SELECT 语句中的条件语句经常要使用比较运算符。通过这些比较运算符,可以判断表中的哪些记录是符合条件的。比较结果为真,则返回 1,为假则返回 0,比较结果不确定则返回 NULL。

符号 描述 备注
= 等于
<>, != 不等于
大于
< 小于
<= 小于等于
>= 大于等于
BETWEEN 在两值之间 between var1 and var2
NOT BETWEEN 不在两值之间
IN 在集合中
NOT IN 不在集合中
<=> 严格比较两个NULL值是否相等 两个操作码均为NULL时,其所得值为1;而当一个操作码为NULL时,其所得值为0
LIKE 模糊匹配
REGEXP 或 RLIKE 正则式匹配 rlike pattern;
IS NULL 为空
IS NOT NULL 不为空
having 过滤 having 过滤条件【通常与select后的函数一起使用】; 在数据分组后用于过滤分组的结果
where 过滤 where 过滤条件; 在数据分组前用于过滤分组的结果

数据导出和导入

导出为sql语句到文件

sql 复制代码
mysqldump -u 用户名字 -p 数据库名字 > output_file_path.sql

查询结果输出到文件

sql 复制代码
select * from 表名字 into outfile './user_table.txt';
-- 大概率会失败,显示没有权限

导入sql文件

sql 复制代码
mysqldump -u 用户名字 -p 数据库名字 < input_file_path.sql

事务

开启事务-显示

sql 复制代码
begin;

-- or 
start transaction;

提交事务

sql 复制代码
commit;

-- or
commit work;

事务回滚【会结束事务】

sql 复制代码
rollback;

-- or
rollback work;

-- 回滚到事务设置的保存点
rollback to savepoint save_rollback_point;

设置事务回滚点

sql 复制代码
savepoint save_rollback_point;

查看当前事务状态

sql 复制代码
show engine innodb status;

锁定表进行事务操作

sql 复制代码
lock tables table_name write;

-- or
lock tables table_name read;

释放锁定的表

sql 复制代码
unlock tables;

一些奇奇怪怪的命令

查看当前用户

sql 复制代码
select user();

退出mysql

sql 复制代码
exit;

刷新权限

sql 复制代码
flush privileges;

索引

索引分类

  1. 主键索引(Primary Key)
    • 每个表只能有一个主键索引。
    • 主键索引确保了每条记录的唯一性,并且不允许NULL值。
    • 它通常是聚簇索引(Clustered Index),意味着数据行本身按照主键的顺序存储。
  2. 唯一索引(Unique Index)
    • 确保索引列中的所有值都是唯一的,但允许存在一个或多个NULL值(取决于存储引擎)。
    • 可以在一个表上创建多个唯一索引。
  3. 普通索引(Index/Secondary Index)
    • 这是最基本的索引类型,可以创建在单个或多个列上。
    • 不强制值的唯一性,也不限制NULL值的存在。
    • 用于加速WHERE子句、ORDER BY、GROUP BY等操作。
  4. 全文索引(Fulltext Index)
    • 专门用于全文搜索,适用于TEXTCHARVARCHAR类型的列。
    • 允许对文本内容进行复杂的搜索,如自然语言搜索、布尔搜索等。
    • 在处理大量文本数据时非常有用。

索引失效

  1. 使用函数或表达式操作索引列:当对索引列应用函数、进行计算或转换时,索引通常会失效。
sql 复制代码
-- YEAR(hire_date) 会导致索引失效。
SELECT * FROM 表名字 WHERE YEAR(字段名字) = 2023;
  1. 类型不匹配:如果索引列的数据类型与查询条件中的数据类型不匹配,可能会导致索引失效。例如,索引列是VARCHAR类型,但查询条件中使用了整数:
sql 复制代码
select * from 表名字 where 字段名字 = 12345;

应确保类型匹配:

sql 复制代码
select * from 表名字 where 字段名字 = '12345';
  1. 使用!=<>:对于不等于的比较(如!=<>),MySQL可能无法有效利用索引,特别是当涉及大量数据时。
  2. like语句开头使用通配符:如果like语句的第一个字符是通配符(如%_),则索引将不会被使用:
sql 复制代码
SELECT * FROM 表名字 WHERE 字段名字 LIKE '%smith';

但如果通配符不在第一个位置,则索引仍然可以被使用:

sql 复制代码
SELECT * FROM 表名字 WHERE 字段名字 LIKE 'smith%';
  1. 使用OR条件:如果OR连接的条件不是全部都是索引列,那么整个OR条件下的索引可能会失效。
sql 复制代码
SELECT * FROM 表名字 WHERE 字段名字1 = 'value' OR 字段名字2 = 'value';

索引语法

建立索引是都指定索引名

  1. 建表时建立索引:看建表部分
  2. 建立普通索引
sql 复制代码
create index 索引名字
on 表名字(字段名字1,字段名字2,...);
  1. 建立唯一索引
sql 复制代码
create unique index 索引名字
on 表名字(字段名字1,字段名字2,...);
  1. 建立全文索引
sql 复制代码
create fulltext index 索引名字
on 表名字(字段名字)
character set character_set_name;
  1. 修改索引:删除索引再添加索引
  2. 删除索引
sql 复制代码
alter table 表名字 drop index 索引名字;

SQL调优

SQL调优是一个系统性工程,涉及索引优化、查询语句重写、表结构设计以及数据库配置等多个层面。以下是结合两者特性的核心SQL调优方法:

索引优化(最核心的手段)

索引是提升查询速度最直接的方法,但滥用索引会降低写入性能。

  1. 遵循最左前缀原则 (Leftmost Prefix)
    • 原理:对于联合索引 (a, b, c),查询条件必须从 a 开始匹配,否则索引失效。
    • 注意:在联合索引中,如果中间列使用了范围查询(>, <, between),后续列的索引将失效。
  2. 避免索引失效的场景
    • 函数操作:不要在索引列上使用函数或计算。
      • WHERE YEAR(create_time) = 2026
      • WHERE create_time >= '2026-01-01' AND create_time < '2027-01-01'
    • 隐式类型转换:字符串类型的字段不要传数字,否则会导致全表扫描。
      • WHERE phone_num = 13800000000 (phone_num 是 varchar)
      • WHERE phone_num = '13800000000'
    • 模糊查询:LIKE '%keyword%'(前缀通配符)会导致索引失效。如果必须使用前缀通配,考虑使用覆盖索引全文索引 (MySQL FullText / SQL Server Full-Text Search)。
    • OR 条件:如果 OR 连接的两个条件中有一个没有索引,整个索引可能失效。建议拆分为 UNION ALL
  3. 覆盖索引 (Covering Index)
    • 概念:查询的列全部包含在索引中,无需回表(Lookup)。
    • 效果:极大减少IO操作。
    • 示例:SELECT id, name FROM user WHERE age = 25,建立 (age, name) 联合索引。
  4. 区分度高的列建索引
    • 性别、状态枚举等区分度低的列,单独建索引效果极差,数据库优化器可能直接放弃索引走全表扫描。

查询语句 (SQL) 重写优化

  1. 只取需要的列 (Avoid SELECT *)

    • 原因:减少网络传输量,增加覆盖索引命中的概率,减少内存消耗。
    • 做法:明确列出所需字段 SELECT id, name ...
  2. 优化 JOIN 操作

    • 小表驱动大表:确保驱动表(外层循环表)数据量较小。
    • 关联字段必须有索引:ON 后面的关联字段在两张表中都应建立索引。
    • 类型一致:关联字段的字符集和排序规则(Collation)必须一致,否则可能导致索引失效。
  3. 分页优化 (LIMIT / OFFSET)

    • 问题:LIMIT 100000, 10 需要扫描前100010条记录并丢弃,效率极低。

    • 优化方案:

      • 延迟关联:先查ID,再回表。
      sql 复制代码
      SELECT t.* FROM table t
      INNER JOIN (SELECT id FROM table LIMIT 100000, 10) tmp ON t.id = tmp.id;
      • 游标法(推荐):记录上一页最大的ID,直接 WHERE id > last_max_id LIMIT 10
  4. EXISTS vs IN

    • 一般情况:现代优化器(MySQL 5.7+/SQL Server 2016+)对两者处理差异不大。
    • 特定场景:
      • 子查询结果集小,主表大:用 IN
      • 子查询结果集大,主表小:用 EXISTS
    • NOT IN:尽量避免使用 NOT IN(特别是子查询包含NULL值时),推荐使用 NOT EXISTSLEFT JOIN ... WHERE ... IS NULL
  5. 批量插入

    • 避免循环单条插入。
    • MySQL: INSERT INTO t VALUES (...), (...), (...);
    • SQL Server: 同样支持多值插入,或使用 BULK INSERT 处理海量数据。

六、调优实战步骤总结

  1. 定位慢SQL:
    • MySQL: 开启慢查询日志 (slow_query_log),或使用 performance_schema
    • SQL Server: 使用 Profiler, Extended Events, 或查询 sys.dm_exec_query_stats
  2. 分析执行计划:找出全表扫描、高成本算子、回表操作。
  3. 检查索引:是否缺失?是否失效?是否多余?
  4. 重写SQL:优化逻辑,去除函数,调整 Join 顺序。
  5. 验证测试:在生产环境镜像或测试环境中验证优化效果,确保没有副作用(如锁竞争加剧)。
  6. 监控:上线后持续观察 CPU、IO 和 响应时间。
相关推荐
kc胡聪聪2 小时前
MySQL的主从复制与读写分离
mysql
皙然2 小时前
深入理解 MySQL 事务:从基础到实战,一篇吃透
数据库·mysql
我科绝伦(Huanhuan Zhou)2 小时前
MySQL数据库备份管理系统新增备份任务巡检功能
运维·数据库·mysql
tuokuac2 小时前
什么情况下type为index
mysql
夕除2 小时前
Mysql--14
数据库·mysql
qq_283720052 小时前
MySQL实战(十五): 常用内置函数实战--日期、字符串、数学函数从入门到精通
mysql·内置函数·日期函数·字符函数·日期计算
Javatutouhouduan3 小时前
SQL优化从入门到精通!
java·数据库·mysql·sql优化·java面试·后端开发·java程序员
刘晨鑫13 小时前
MySQL主从复制与读写分离
数据库·mysql·adb
ClouGence3 小时前
数据迁移同步工具 CloudCanal-v5.5.0.0 发布,支持 RETL(定时扫描同步)
数据库·mysql·postgresql·oracle·sqlserver·kafka·etl