MySQL开启binlog日志,恢复数据教程

前言

误删了数据,有备份但太老了,怎么办?开启binlog可以恢复到任意时间点的数据。

一、什么是binlog

binlog是MySQL的二进制日志,记录所有写操作(增删改)。

作用:

  1. 数据恢复
  2. 主从复制

二、开启binlog

查看是否开启

SHOW VARIABLES LIKE 'log_bin';
Variable_name Value
log_bin OFF

OFF就是没开。

开启方法

改my.cnf:

[mysqld]
# 开启binlog
log_bin = /var/log/mysql/mysql-bin

# 服务ID
server_id = 1

# binlog格式(推荐row)
binlog_format = ROW

# 保留7天
expire_logs_days = 7

# 单个文件最大1G
max_binlog_size = 1G

重启MySQL:

systemctl restart mysqld

验证开启成功

SHOW VARIABLES LIKE 'log_bin';

显示ON就是开了。

三、查看binlog文件

SHOW BINARY LOGS;

输出:

Log_name File_size
mysql-bin.000001 123456
mysql-bin.000002 234567

四、恢复数据

场景:误删了表,要恢复

第一步:找到要恢复的位置

先看binlog内容:

mysqlbinlog /var/log/mysql/mysql-bin.000002

找到误操作的位置点(position)。

第二步:恢复到备份点

先恢复最近的全量备份:

mysql -u root -p < backup.sql

第三步:恢复binlog

从备份点开始,恢复binlog到误操作前:

mysqlbinlog --start-position=备份点position --stop-position=误操作前position /var/log/mysql/mysql-bin.000002 | mysql -u root -p

按时间恢复

mysqlbinlog --start-datetime="2026-10-08 07:00:00" --stop-datetime="2026-10-08 07:30:00" /var/log/mysql/mysql-bin.000002 | mysql -u root -p

五、常用操作

刷新binlog(新开一个文件)

FLUSH LOGS;

删除旧binlog

-- 删除指定文件之前的
PURGE BINARY LOGS TO 'mysql-bin.000010';

-- 删除7天前的
PURGE BINARY LOGS BEFORE DATE(NOW() - INTERVAL 7 DAY);

查看当前binlog位置

SHOW MASTER STATUS;

六、binlog格式

格式 说明 优缺点
STATEMENT 记录SQL语句 日志小,但可能不一致
ROW 记录每行变化 日志大,但精确
MIXED 混合 折中

推荐用ROW,最安全。

常见坑

坑1:binlog没开就想恢复

原因: 事前没开启binlog。

解决: 现在就去开,不然出事就晚了。

坑2:binlog格式不对

用STATEMENT格式,恢复后数据不一致。

解决: 用ROW格式。

坑3:binlog占满磁盘

binlog一直写,磁盘满了。

解决: 设 expire_logs_days = 7,自动删旧的。

坑4:恢复顺序错了

先恢复binlog再恢复备份,数据更旧了。

正确顺序: 先恢复全量备份 → 再恢复binlog增量。

坑5:mysqlbinlog命令找不到

原因: MySQL环境变量没配。

解决: 用全路径:

/usr/local/mysql/bin/mysqlbinlog

总结

开启binlog三步:

  1. 改my.cnf加 log_bin
  2. 重启MySQL
  3. 验证 SHOW VARIABLES LIKE 'log_bin'

记住: 生产环境一定要开binlog,不然出事就完蛋。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:50 

MySQL查看数据库大小,表占用空间

前言

磁盘快满了,不知道哪个库哪个表占空间大。本文教你查MySQL数据库和表的大小。

一、查看所有数据库大小

SELECT 
    table_schema AS '数据库名',
    ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS '大小(MB)'
FROM information_schema.tables
GROUP BY table_schema
ORDER BY SUM(data_length + index_length) DESC;

输出:

数据库名 大小(MB)
mydb 512.34
test 128.56
mysql 10.24

二、查看某个数据库的所有表大小

SELECT 
    table_name AS '表名',
    ROUND(((data_length + index_length) / 1024 / 1024), 2) AS '大小(MB)',
    table_rows AS '行数'
FROM information_schema.tables
WHERE table_schema = 'mydb'
ORDER BY (data_length + index_length) DESC;

把 mydb 换成你的数据库名。

三、查看单个表大小

SELECT 
    table_name AS '表名',
    ROUND((data_length) / 1024 / 1024, 2) AS '数据大小(MB)',
    ROUND((index_length) / 1024 / 1024, 2) AS '索引大小(MB)',
    table_rows AS '行数'
FROM information_schema.tables
WHERE table_schema = 'mydb' AND table_name = 'users';

四、查看所有表大小(按大小排序)

SELECT 
    table_schema AS '数据库',
    table_name AS '表名',
    ROUND(((data_length + index_length) / 1024 / 1024), 2) AS '大小(MB)',
    table_rows AS '行数'
FROM information_schema.tables
ORDER BY (data_length + index_length) DESC
LIMIT 20;

只看前20大的表。

五、用命令行查看

查看数据目录

du -sh /var/lib/mysql/

查看某个库的大小

du -sh /var/lib/mysql/mydb/

查看所有库的大小

du -sh /var/lib/mysql/*/

六、常用场景

场景1:磁盘满了,找大表

SELECT 
    table_schema AS '数据库',
    table_name AS '表名',
    ROUND(((data_length + index_length) / 1024 / 1024), 2) AS '大小(MB)'
FROM information_schema.tables
ORDER BY (data_length + index_length) DESC
LIMIT 10;

找出最大的10个表。

场景2:表很大,想知道数据和索引各占多少

SELECT 
    table_name AS '表名',
    ROUND(data_length / 1024 / 1024, 2) AS '数据(MB)',
    ROUND(index_length / 1024 / 1024, 2) AS '索引(MB)'
FROM information_schema.tables
WHERE table_schema = 'mydb';

场景3:清理无用数据,释放空间

删了很多数据,但磁盘空间没释放。

原因: InnoDB删数据后不会自动释放磁盘空间。

解决: 优化表:

OPTIMIZE TABLE users;

常见坑

坑1:table_rows不准

InnoDB的table_rows是估算值,不是精确值。

原因: InnoDB是多版本的,统计信息不精确。

解决: 要精确行数用 SELECT COUNT(*) FROM 表名;

坑2:删了数据空间没释放

DELETE删了很多行,但文件大小没变。

原因: InnoDB的表空间不会自动收缩。

解决: OPTIMIZE TABLE 表名; 或者重建表。

坑3:临时表占空间

performance_schema等系统库也占空间。

解决: 正常现象,不用管。

坑4:ibdata1文件很大

共享表空间文件很大,但不知道里面是什么。

原因: 所有InnoDB表都存在一个文件里。

解决: 开 innodb_file_per_table,每个表独立文件。

总结

常用查询:

  1. 查所有库大小:GROUP BY table_schema
  2. 查某库所有表:WHERE table_schema='库名'
  3. 查某表大小:WHERE table_schema='库名' AND table_name='表名'

记住: 磁盘满了先查information_schema.tables找大表。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:49 

MySQL删除表、清空表,truncate和delete区别

前言

清空表数据,用DELETE还是TRUNCATE?删表用DROP?很多人搞混,本文讲清楚区别。

三种操作

1. DELETE:删行

-- 删指定行
DELETE FROM users WHERE id = 1;

-- 删全表
DELETE FROM users;

特点:

  • 一行一行删,慢
  • 可以加WHERE条件
  • 可以回滚(在事务里)
  • 自增ID不重置,继续从之前的数开始
  • 会写binlog

2. TRUNCATE:清空表

TRUNCATE TABLE users;

特点:

  • 直接删表重建,快
  • 不能加WHERE条件
  • 不能回滚
  • 自增ID重置,从1开始
  • 比DELETE快很多

3. DROP:删表

DROP TABLE users;

特点:

  • 表结构+数据全删
  • 表都没了
  • 最快

对比表

对比项 DELETE TRUNCATE DROP
删什么 删行 删表重建 删表
速度 慢 快 最快
WHERE 支持 不支持 不支持
回滚 可以 不可以 不可以
自增ID 不重置 重置 表都没了
表结构 保留 保留 删除
写binlog 是 是(默认) 是

什么时候用哪个

用DELETE

  • 只删部分数据(带WHERE)
  • 需要回滚
  • 数据量小

用TRUNCATE

  • 清空全表数据
  • 数据量大,要快
  • 不需要回滚

用DROP

  • 表不要了
  • 表结构也删

常见坑

坑1:DELETE删全表很慢

DELETE FROM users;

100万行删半天。

解决: 清空全表用 TRUNCATE TABLE users;

坑2:TRUNCATE不能回滚

执行TRUNCATE后想后悔,回不去了。

解决: 执行前先备份,或者用DELETE(慢但能回滚)。

坑3:TRUNCATE自增ID重置

清空表后,自增ID从1开始了。

原因: TRUNCATE会重建表。

解决: 如果不想重置自增ID,用DELETE。

坑4:外键约束导致TRUNCATE失败

ERROR 1701 (42000): Cannot truncate a table referenced in a foreign key constraint

原因: 有其他表的外键关联到这个表。

解决: 先关外键检查:

SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE TABLE users;
SET FOREIGN_KEY_CHECKS = 1;

坑5:DELETE不写WHERE删全表

手滑了,没写WHERE,把全表删了。

解决: 执行DELETE前,先SELECT一下看条件对不对。

性能对比

操作 10万行 100万行
DELETE全表 几十秒 几分钟
TRUNCATE 0.01秒 0.01秒
DROP 0.01秒 0.01秒

TRUNCATE和DROP都是秒级,DELETE要逐行删。

总结

一句话总结:

  • 删部分数据 → DELETE
  • 清空全表 → TRUNCATE
  • 表不要了 → DROP

记住: 清空表别用DELETE,太慢了。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:48 

MySQL优化查询速度,explain分析执行计划

前言

SQL查得慢,不知道为什么慢。用EXPLAIN看MySQL怎么执行这条SQL,就能找到问题在哪。

一、EXPLAIN怎么用

EXPLAIN SELECT * FROM users WHERE name = '张三';

输出很多列,重点看这几个:id、select_type、table、type、key、rows、Extra。

二、重点列详解

1. type(访问类型)

最重要的一列,看SQL查得快不快。

从好到差:

type 说明 速度
system 表只有一行 最快
const 主键或唯一索引查一次 很快
eq_ref 联表时主键关联 很快
ref 非唯一索引查 快
range 索引范围扫描 中
index 扫整个索引树 慢
ALL 全表扫描 最慢

目标: 至少达到range,最好是ref以上。

如果type是ALL,就是全表扫描,必须优化。

2. key(实际用到的索引)

key: NULL

说明没用索引。

key: idx_name

说明用到了idx_name索引。

3. rows(扫描行数)

MySQL预估要扫描多少行。

rows越大,越慢。

4. Extra(额外信息)

常见的:

  • Using where:WHERE过滤
  • Using index:覆盖索引,不用回表,好
  • Using filesort:需要额外排序,不好
  • Using temporary:用了临时表,不好

三、常见问题

问题1:type=ALL,全表扫描

原因: 没加索引,或者索引失效。

解决: 给WHERE条件的字段加索引。

问题2:key=NULL,没用索引

原因:

  1. 没建索引
  2. 索引失效了(函数、类型转换、前导模糊查询等)

解决: 建正确的索引,避免索引失效写法。

问题3:Using filesort

原因: ORDER BY的字段没走索引。

解决: 给ORDER BY的字段加索引。

问题4:Using temporary

原因: GROUP BY或DISTINCT用了临时表。

解决: 给GROUP BY的字段加索引。

四、实战案例

慢SQL

SELECT * FROM orders WHERE user_id = 100 ORDER BY create_time DESC LIMIT 10;

EXPLAIN结果:

id select_type table type key rows Extra
1 SIMPLE orders ALL NULL 100000 Using where; Using filesort

问题:

  1. type=ALL,全表扫描
  2. key=NULL,没用索引
  3. rows=100000,扫了10万行
  4. Using filesort,还要额外排序

优化

加联合索引:

ALTER TABLE orders ADD INDEX idx_userid_createtime (user_id, create_time);

再EXPLAIN:

id select_type table type key rows Extra
1 SIMPLE orders ref idx_userid_createtime 10 Using where

优化效果:

  1. type变成ref
  2. 用到了索引
  3. rows从10万变成10
  4. 没有filesort了

五、常用优化技巧

1. 避免SELECT *

只查需要的列,能用上覆盖索引。

2. WHERE条件加索引

经常查询的字段加索引。

3. 联合索引最左前缀

联合索引 (a,b,c),查询条件要从最左列开始。

4. 避免索引失效

  • 不要对索引字段用函数
  • 不要隐式类型转换
  • 不要前导模糊查询 like '%xxx'

总结

EXPLAIN看这三点:

  1. type:是不是全表扫描
  2. key:有没有用到索引
  3. rows:扫描了多少行

记住: 慢SQL先EXPLAIN,找到问题再优化。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:47 

MySQL远程连接失败,权限和防火墙问题

前言

本地能连MySQL,远程连接就报错。常见原因:用户没授权、防火墙没开、MySQL只监听本地。

报错长什么样

ERROR 2003 (HY000): Can't connect to MySQL server on 'xxx.xxx.xxx.xxx'

或者:

ERROR 1130 (HY000): Host 'xxx.xxx.xxx.xxx' is not allowed to connect to this MySQL server

原因一:用户没授权远程登录

排查

SELECT user, host FROM mysql.user;

看root用户的host是 localhost 还是 %。

如果是 localhost,就只能本地登录。

解决

授权远程登录:

-- 方法1:授权root所有IP
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '你的密码';

-- 方法2:只允许某个IP
GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.1.100' IDENTIFIED BY '你的密码';

-- 刷新
FLUSH PRIVILEGES;

原因二:防火墙没开3306端口

排查

在本地服务器上测试:

netstat -tlnp | grep 3306

看MySQL监听的是 127.0.0.1:3306 还是 0.0.0.0:3306。

如果是 127.0.0.1:3306,说明只监听本地。

解决防火墙

CentOS7 firewalld

# 开3306端口
firewall-cmd --permanent --add-port=3306/tcp

# 重载
firewall-cmd --reload

Ubuntu ufw

ufw allow 3306/tcp

原因三:MySQL只监听本地

排查

netstat -tlnp | grep 3306

如果显示 127.0.0.1:3306,就是只监听本地。

解决

改my.cnf:

[mysqld]
bind-address = 0.0.0.0

注释掉 skip-networking(如果有的话)。

重启MySQL:

systemctl restart mysqld

原因四:云服务器安全组

阿里云、腾讯云等云服务器,除了系统防火墙,还有安全组。

解决

在云服务器控制台,找到安全组,放行3306端口。

原因五:MySQL版本问题

MySQL 8.0默认用 caching_sha2_password,老客户端不支持。

解决

创建用户时指定老的加密方式:

CREATE USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '你的密码';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';
FLUSH PRIVILEGES;

排查步骤

第一步:本地能连吗

先在服务器上本地连一下:

mysql -u root -p

本地能连,说明MySQL本身没问题。

第二步:看MySQL监听地址

netstat -tlnp | grep 3306

第三步:防火墙开了吗

firewall-cmd --list-ports

看3306在不在。

第四步:远程telnet测试

在本地电脑上测试:

telnet 服务器IP 3306

如果连不上,就是网络/防火墙问题。

常见坑

坑1:改了授权忘了刷新

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';

改完就退出,结果还是连不上。

解决: 执行 FLUSH PRIVILEGES;

坑2:bind-address没改

授权了,防火墙也开了,还是连不上。

原因: MySQL只监听本地。

解决: 改 bind-address = 0.0.0.0

坑3:安全组没开

系统防火墙开了,云服务器安全组没开。

解决: 去云控制台放行3306端口。

坑4:密码不对

报错不是"连接不上",而是"Access denied"。

原因: 密码错了。

解决: 确认密码,注意大小写。

总结

远程连接失败排查顺序:

  1. 先授权远程用户
  2. 再开防火墙3306
  3. 然后改bind-address
  4. 最后查云安全组

记住: 90%的情况都是没授权或者防火墙没开。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:45 

MySQL修改root密码,多种方法汇总

前言

知道旧密码,想改个新密码,有好几种方法。本文汇总常用的改密码方法。

方法一:ALTER USER(推荐)

登录MySQL后:

ALTER USER 'root'@'localhost' IDENTIFIED BY '你的新密码';

然后刷新:

FLUSH PRIVILEGES;

优点: 官方推荐,语法标准,MySQL 5.7/8.0都支持。

方法二:SET PASSWORD

SET PASSWORD FOR 'root'@'localhost' = PASSWORD('你的新密码');

刷新:

FLUSH PRIVILEGES;

注意: MySQL 8.0以后 PASSWORD() 函数被删了,不能用了。

方法三:UPDATE直接改

UPDATE mysql.user SET authentication_string=PASSWORD('你的新密码') 
WHERE User='root' AND Host='localhost';

刷新:

FLUSH PRIVILEGES;

注意: 同样,MySQL 8.0不能用PASSWORD()函数。

方法四:命令行修改

不用登录MySQL,直接命令行:

mysqladmin -u root -p password "你的新密码"

输入旧密码后,就改成新密码了。

MySQL 8.0改密码

MySQL 8.0改密码语法有变化:

方法一:ALTER USER(推荐)

ALTER USER 'root'@'localhost' IDENTIFIED BY '你的新密码';

方法二:SET PASSWORD

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的新密码';

不同Host的root用户

root可能有多个:

SELECT user, host FROM mysql.user WHERE user='root';

输出可能是:

user host
root localhost
root 127.0.0.1
root %

每个host的root密码是独立的,要分别改。

ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';
ALTER USER 'root'@'127.0.0.1' IDENTIFIED BY '新密码';
ALTER USER 'root'@'%' IDENTIFIED BY '新密码';

常见坑

坑1:改了密码还是旧密码能登

原因: 没执行 FLUSH PRIVILEGES;

解决: 改完密码一定要刷新权限。

坑2:MySQL 8.0报语法错误

ERROR 1064 (42000): You have an error in your SQL syntax

原因: 用了 PASSWORD() 函数,MySQL 8.0删了。

解决: 用 ALTER USER 语句。

坑3:改了密码远程登不上

本地能登,远程连不上。

原因: 只改了localhost的密码,远程用户的密码没改。

解决: 把所有host的root密码都改了。

坑4:密码太简单报错

ERROR 1819 (HY000): Your password does not satisfy the current policy requirements

原因: MySQL密码强度校验太严。

解决: 用复杂点的密码(大小写+数字+特殊字符),或者关掉密码校验:

SET GLOBAL validate_password_policy=LOW;

坑5:改完密码phpStudy/phpMyAdmin连不上

原因: 站点配置文件里的密码还是旧的。

解决: 改项目配置文件里的数据库密码。

总结

知道旧密码改密码:

方法 适用版本 推荐度
ALTER USER 5.7/8.0 推荐
SET PASSWORD 5.7及以前 一般
UPDATE mysql.user 5.7及以前 不推荐
mysqladmin 所有版本 一般

记住: 改完密码一定要 FLUSH PRIVILEGES;

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:44 

MySQL查看当前连接数,show processlist

前言

MySQL连接数太多,报"Too many connections",怎么看当前有多少连接?哪些连接在跑什么SQL?用show processlist。

一、查看当前连接

基本命令

SHOW PROCESSLIST;

输出:

Id User Host db Command Time State Info
123 root localhost:54321 mydb Query 0 starting SHOW PROCESSLIST
124 www 192.168.1.100:1234 mydb Sleep 30 NULL

每列含义:

  • Id:连接ID,kill的时候用
  • User:用户名
  • Host:客户端IP和端口
  • db:当前数据库
  • Command:当前命令(Query/Sleep/Connect)
  • Time:当前状态持续时间(秒)
  • State:状态
  • Info:正在执行的SQL

显示完整SQL

SHOW FULL PROCESSLIST;

默认Info列只显示前100个字符,加FULL显示完整SQL。

二、查看连接数

当前连接数

SHOW STATUS LIKE 'Threads_connected';

最大连接数

SHOW VARIABLES LIKE 'max_connections';

历史最大连接数

SHOW STATUS LIKE 'Max_used_connections';

三、杀掉连接

杀掉某个连接

KILL 连接ID;

比如杀掉ID为123的连接:

KILL 123;

杀掉所有Sleep连接

-- 先查出来
SELECT CONCAT('KILL ', id, ';') FROM information_schema.processlist 
WHERE user = 'www' AND command = 'Sleep';

把结果复制出来执行,就能批量杀掉。

四、常用查询

按用户统计连接数

SELECT user, COUNT(*) FROM information_schema.processlist 
GROUP BY user;

按IP统计连接数

SELECT SUBSTRING_INDEX(host, ':', 1) AS ip, COUNT(*) 
FROM information_schema.processlist 
GROUP BY ip;

查看执行超过10秒的SQL

SELECT * FROM information_schema.processlist 
WHERE time > 10;

五、调整最大连接数

临时调整

SET GLOBAL max_connections = 1000;

永久调整

改my.cnf:

[mysqld]
max_connections = 1000

重启MySQL生效。

常见坑

坑1:Sleep连接太多

大量Sleep连接占着连接数,导致新连接进不来。

原因: 程序没关连接,连接池没配好。

解决:

  1. 调小 wait_timeout,让空闲连接自动断开
  2. 检查程序连接池配置
SET GLOBAL wait_timeout = 60;

坑2:看不到其他用户的连接

普通用户只能看到自己的连接。

解决: 用root用户登录,或者PROCESS权限。

坑3:kill了连接还在

kill了连接,但连接还在列表里。

原因: 连接正在回滚,需要等一会。

解决: 等几秒再看,或者重启MySQL。

坑4:连接数突然暴涨

突然一堆连接进来,数据库卡死。

原因: 可能是程序bug,或者被攻击了。

排查: 按IP统计,看哪个IP连接最多。

总结

常用命令:

命令 作用
SHOW PROCESSLIST 看当前连接
SHOW FULL PROCESSLIST 看完整SQL
SHOW STATUS LIKE 'Threads_connected' 看当前连接数
KILL 连接ID 杀掉连接

记住: 连接数满了先看processlist,找出是谁占着连接。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:43 

MySQL报错"Table 'xxx' doesn't exist"解决

前言

查询数据库时报错:Table 'xxx' doesn't exist,明明表就在那,为什么说不存在?本文排查常见原因。

报错长什么样

SELECT * FROM users;

报错:

ERROR 1146 (42S02): Table 'mydb.users' doesn't exist

常见原因

原因1:数据库选错了

当前在别的库里,所以找不到表。

排查: 先看当前在哪个库:

SELECT DATABASE();

如果显示的不是你要的库,就切换:

USE mydb;

再查一次。

原因2:表名写错了

拼错了,或者大小写不对。

排查: 看看库里到底有哪些表:

SHOW TABLES;

确认表名是不是和你写的一模一样。

注意: Linux下MySQL表名区分大小写,Users 和 users 是两个表。

原因3:表真的被删了

表确实不存在了,可能被误删了。

排查: 用SHOW TABLES确认。如果真没有,从备份恢复。

原因4:字符集导致的问题

表名里有特殊字符,编码不对导致识别不出来。

排查: 用 SHOW TABLES LIKE 'xxx%'; 模糊匹配一下。

原因5:MySQL升级后表损坏

升级MySQL后,某些表报错不存在,但文件还在。

原因: 表引擎损坏,或者frm文件丢了。

排查: 看数据目录下有没有对应文件:

ls /var/lib/mysql/mydb/

原因6:用户没有权限

虽然报错是"不存在",但有时候权限不够也会这么报。

排查: 用root用户登录试试,如果root能看到,就是权限问题。

排查步骤

第一步:确认当前数据库

SELECT DATABASE();

第二步:查看所有表

SHOW TABLES;

第三步:模糊搜索表名

SHOW TABLES LIKE '%user%';

第四步:确认表文件是否存在

ls /var/lib/mysql/你的库名/ | grep 表名

常见坑

坑1:Linux下表名区分大小写

Windows开发没问题,上传到Linux服务器就报错。

解决: 表名统一用小写,或者在my.cnf加:

lower_case_table_names = 1

注意: 这个参数只能在初始化MySQL前设置,已经用了再改会出问题。

坑2:分表了忘了加表名

用了分表,代码里查的是 users,实际表名是 users_0、users_1。

解决: 确认分表规则,代码里拼对表名。

坑3:视图报错

查视图时报"表不存在",可能是视图依赖的表被删了。

排查: 看视图定义:

SHOW CREATE VIEW 视图名;

坑4:临时表

会话结束临时表就没了,新开一个连接查就报错。

解决: 临时表只在当前会话有效,别跨连接用。

坑5:误删了库

整个库都没了,当然找不到表。

排查:

SHOW DATABASES;

看你的库还在不在。

总结

排查顺序:

  1. 先看当前在哪个库
  2. 再SHOW TABLES看表在不在
  3. 确认表名大小写对不对
  4. 最后看数据目录下文件在不在

记住: 90%的情况都是库选错了或者表名写错了。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:41 

MySQL查看表结构,desc和show create table

前言

接手别人的项目,不知道表有哪些字段、什么类型、有没有索引,全靠DESC和SHOW CREATE TABLE。

一、查看表有哪些字段

方法1:DESC(最常用)

DESC users;

或者:

DESCRIBE users;

输出:

Field Type Null Key Default Extra
id int(11) NO PRI NULL auto_increment
name varchar(50) YES NULL
age int(11) YES NULL

每列含义:

  • Field:字段名
  • Type:字段类型
  • Null:能不能为NULL
  • Key:有没有索引
  • Default:默认值
  • Extra:额外属性(自增等)

方法2:SHOW COLUMNS

SHOW COLUMNS FROM users;

和DESC效果一样,写法不同而已。

二、查看建表语句

SHOW CREATE TABLE

SHOW CREATE TABLE users;

输出:

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

这个命令能看到:

  • 完整的建表SQL
  • 所有字段和类型
  • 主键、索引
  • 表引擎、字符集
  • 默认值、自增等

三、查看表状态

SHOW TABLE STATUS LIKE 'users'\G

能看到:

  • 表行数
  • 数据大小
  • 索引大小
  • 更新时间
  • 引擎类型
  • 字符集

四、查看表的所有索引

SHOW INDEX FROM users;

或者:

SHOW KEYS FROM users;

五、查看数据库里所有表

SHOW TABLES;

六、实用组合

查看所有表的表名

SHOW TABLES;

查看某库的表

USE 数据库名;
SHOW TABLES;

或者:

SHOW TABLES FROM 数据库名;

七、从information_schema查

更灵活的方式,从系统表查:

查表的字段信息

SELECT * FROM information_schema.COLUMNS 
WHERE TABLE_SCHEMA = 'mydb' 
AND TABLE_NAME = 'users';

查表的索引信息

SELECT * FROM information_schema.STATISTICS 
WHERE TABLE_SCHEMA = 'mydb' 
AND TABLE_NAME = 'users';

常见坑

坑1:DESC看不到索引详细信息

DESC只告诉你Key列是啥,但不知道索引名。

解决: 用 SHOW INDEX FROM 表名;

坑2:SHOW CREATE TABLE输出太长

直接看会换行很乱。

解决: 加 \G 按行显示:

SHOW CREATE TABLE users\G

坑3:不知道当前在哪个库

查的时候报错说表不存在。

解决: 先 SELECT DATABASE(); 看当前库。

坑4:表名大小写问题

Linux下MySQL表名区分大小写,Windows不区分。

解决: 表名小写,开发时注意。

总结

常用命令总结:

命令 作用
DESC 表名 看字段列表
SHOW CREATE TABLE 表名 看完整建表语句
SHOW INDEX FROM 表名 看索引
SHOW TABLES 看所有表
SHOW TABLE STATUS 看表状态

记住: 看表结构首选DESC,要看完整建表语句用SHOW CREATE TABLE。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:40 

MySQL备份数据库,mysqldump定时备份

前言

数据库不备份,出事就完蛋。本文讲用mysqldump备份MySQL,再配crontab定时自动备份。

一、mysqldump基本用法

备份单个数据库

mysqldump -u root -p mydb > /backup/mydb.sql

输入密码后,就把mydb库备份到mydb.sql了。

备份多个数据库

mysqldump -u root -p --databases db1 db2 > /backup/mydbs.sql

备份所有数据库

mysqldump -u root -p --all-databases > /backup/all.sql

备份单个表

mysqldump -u root -p mydb users > /backup/users.sql

二、常用参数

参数 说明
--single-transaction InnoDB一致性备份,不锁表
--routines 备份存储过程和函数
--triggers 备份触发器
--events 备份事件调度器
--master-data=2 记录binlog位置,用于主从
--default-character-set=utf8mb4 指定字符集

推荐完整命令

mysqldump -u root -p \
  --single-transaction \
  --routines \
  --triggers \
  --events \
  --default-character-set=utf8mb4 \
  mydb > /backup/mydb_$(date +%Y%m%d).sql

三、压缩备份

备份完太大,直接压缩:

mysqldump -u root -p mydb | gzip > /backup/mydb.sql.gz

恢复的时候:

gunzip < /backup/mydb.sql.gz | mysql -u root -p mydb

四、定时备份脚本

创建备份脚本:

vi /usr/local/bin/mysql_backup.sh

内容:

#!/bin/bash

# 备份目录
BACKUP_DIR=/backup/mysql

# 数据库配置
DB_USER=root
DB_PASS=你的密码
DB_NAME=mydb

# 创建备份目录
mkdir -p $BACKUP_DIR

# 备份文件名(带日期)
DATE=$(date +%Y%m%d_%H%M%S)
FILE=$BACKUP_DIR/${DB_NAME}_${DATE}.sql.gz

# 执行备份
mysqldump -u$DB_USER -p$DB_PASS \
  --single-transaction \
  --routines \
  --triggers \
  --default-character-set=utf8mb4 \
  $DB_NAME | gzip > $FILE

# 删除7天前的备份
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete

echo "备份完成:$FILE"

加执行权限:

chmod +x /usr/local/bin/mysql_backup.sh

五、配置crontab定时任务

编辑crontab:

crontab -e

加上:

# 每天凌晨2点备份
0 2 * * * /usr/local/bin/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1

六、恢复备份

恢复普通备份

mysql -u root -p mydb < /backup/mydb.sql

恢复压缩备份

gunzip < /backup/mydb.sql.gz | mysql -u root -p mydb

常见坑

坑1:密码写在命令行里不安全

mysqldump -u root -p123456 mydb > xxx.sql

这样密码会出现在进程列表里。

安全做法: 用配置文件存密码。

# /root/.my.cnf
[mysqldump]
user=root
password=你的密码

权限设600:

chmod 600 /root/.my.cnf

以后备份就不用输密码了:

mysqldump mydb > xxx.sql

坑2:备份时锁表

大库备份的时候,业务卡住了。

原因: 没加 --single-transaction。

解决: InnoDB库一定要加这个参数。

坑3:备份文件是空的

备份完一看,文件0字节。

原因: 密码错了,或者数据库名错了。

解决: 先手动执行一次,看报错。

坑4:备份没包含存储过程

备份后恢复,发现存储过程没了。

原因: mysqldump默认不备份存储过程。

解决: 加 --routines 参数。

总结

三步搞定自动备份:

  1. 写备份脚本
  2. 配crontab定时执行
  3. 定期清理旧备份

记住: 备份了不算数,能恢复才算数。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:39 

MySQL创建数据库、创建用户、授权完整命令

前言

新装MySQL,要创建数据库、创建用户、授权,一套操作下来经常懵。本文整理完整命令,照着抄就行。

第一步:登录MySQL

mysql -u root -p

输入root密码登录。

第二步:创建数据库

CREATE DATABASE mydb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

说明:

  • mydb 是数据库名,自己改
  • utf8mb4 支持emoji,推荐用
  • utf8mb4_general_ci 是排序规则

第三步:创建用户

MySQL 5.7及以前

CREATE USER 'myuser'@'localhost' IDENTIFIED BY '你的密码';

MySQL 8.0

CREATE USER 'myuser'@'localhost' IDENTIFIED BY '你的密码';

允许远程登录

CREATE USER 'myuser'@'%' IDENTIFIED BY '你的密码';

% 表示所有IP都能连,生产环境建议指定具体IP。

第四步:授权

授权所有权限(常用)

GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'localhost';

说明:

  • mydb.* 表示mydb库下所有表
  • 要授权所有库就写 *.*

只授权查询权限

GRANT SELECT ON mydb.* TO 'myuser'@'localhost';

授权指定权限

GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'myuser'@'localhost';

授权远程用户

GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'%';

第五步:刷新权限

FLUSH PRIVILEGES;

这步必须做! 不然授权不生效。

查看和撤销权限

查看用户权限

SHOW GRANTS FOR 'myuser'@'localhost';

撤销权限

REVOKE ALL PRIVILEGES ON mydb.* FROM 'myuser'@'localhost';

删除用户

DROP USER 'myuser'@'localhost';

常见坑

坑1:创建了用户但没授权

用户登录上了,但什么都做不了。

原因: 只创建了用户,没授权。

解决: 创建用户后一定要 GRANT。

坑2:改了密码不生效

改完密码还是旧密码能登。

原因: 没 FLUSH PRIVILEGES。

解决: 执行 FLUSH PRIVILEGES;

坑3:远程连接不上

本地能登,远程连不上。

原因: 用户只允许localhost登录。

解决: 创建 '用户'@'%' 的远程用户,或者授权。

坑4:密码太简单报错

创建用户时报密码不符合策略。

原因: MySQL 5.6以后有密码强度校验。

解决: 用复杂点的密码,或者关掉密码校验。

坑5:MySQL 8.0密码加密方式变了

老客户端连不上MySQL 8.0。

原因: MySQL 8.0默认用caching_sha2_password,老客户端不支持。

解决: 创建用户时指定老的加密方式:

CREATE USER 'myuser'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码';

完整一键脚本

-- 登录MySQL后执行
CREATE DATABASE mydb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER 'myuser'@'localhost' IDENTIFIED BY '你的密码';
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'localhost';
FLUSH PRIVILEGES;

总结

三步走:

  1. 建库 CREATE DATABASE
  2. 建用户 CREATE USER
  3. 授权 GRANT + FLUSH PRIVILEGES

记住: 授权完一定要刷新!

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:38 

MySQL大表分页越查越慢,优化方案

前言

大表分页查询,第一页很快,第十页就慢,第一百页直接卡死。这是MySQL分页的经典问题,本文讲怎么优化。

为什么越往后越慢

普通分页:

SELECT * FROM orders ORDER BY id LIMIT 100000, 10;

MySQL 会先扫描前100010条,然后丢掉前100000条,只返回最后10条。

越往后翻,扫描的行越多,当然越慢。

优化方案一:子查询优化

先查出起始位置的id,再用id做条件:

SELECT * FROM orders 
WHERE id >= (SELECT id FROM orders ORDER BY id LIMIT 100000, 1)
LIMIT 10;

原理: 子查询走索引,只查id列,很快。然后外层用id直接定位,不用扫那么多行。

优化方案二:游标分页(推荐)

记住上一页最后一条的id,下次从这个id之后查:

-- 第一页
SELECT * FROM orders ORDER BY id LIMIT 10;

-- 第二页(假设上一页最后id是100)
SELECT * FROM orders WHERE id > 100 ORDER BY id LIMIT 10;

-- 第三页(假设上一页最后id是110)
SELECT * FROM orders WHERE id > 110 ORDER BY id LIMIT 10;

优点: 不管翻到第几页,都是直接定位,速度一样快。

缺点: 不能跳页,只能上一页下一页。

优化方案三:覆盖索引

只查需要的列,不要 SELECT *:

SELECT id, title, create_time FROM orders ORDER BY id LIMIT 100000, 10;

如果查询的列都在索引里,MySQL直接从索引返回数据,不用回表,快很多。

优化方案四:业务上限制深分页

根本解决: 不让用户翻到那么深。

  1. 搜索结果只显示前100页
  2. 用条件过滤,不要全表翻
  3. 用搜索引擎(ES)代替深分页

常见坑

坑1:用了offset就一定慢

其实offset小的时候(比如前10页),差别不大。

结论: 数据量不大的时候,普通分页就行,不用过度优化。

坑2:游标分页不能用排序

游标分页只能按主键或唯一索引排序。

解决: 如果按其他字段排序,先查出对应的id列表,再用id定位。

坑3:子查询效率也不高

子查询在MySQL 5.6以前有优化器问题。

解决: MySQL 5.6以后子查询优化得很好了,放心用。

坑4:没加where条件

深分页没加where,全表扫描。

解决: 尽量加上时间范围、状态等过滤条件。

性能对比

方案 第1页 第100页 第1000页
普通分页 快 慢 很慢
子查询优化 快 中 慢
游标分页 快 快 快
搜索引擎 快 快 快

总结

大表分页优化三板斧:

  1. 小数据量:普通分页就行
  2. 中等数据量:子查询优化
  3. 大数据量:游标分页 + 搜索引擎

记住: 深分页不是MySQL擅长的事,数据量大了就上ES。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:36 

MySQL数据库导入sql文件报错解决

前言

导入SQL文件到MySQL,经常报各种错。本文总结最常见的导入报错和解决方法。

常用导入命令

mysql -u root -p 数据库名 < xxx.sql

或者登录MySQL后:

source /路径/xxx.sql;

常见报错及解决

报错1:Unknown database

ERROR 1049 (42000): Unknown database 'xxx'

原因: 数据库不存在。

解决: 先创建数据库:

CREATE DATABASE xxx DEFAULT CHARSET utf8mb4;

然后再导入。

报错2:Access denied

ERROR 1044 (42000): Access denied for user

原因: 用户没权限。

解决: 用root用户导入,或者给用户授权。

报错3:File not found

ERROR 1045 (28000): Access denied

或者文件找不到。

原因: 文件路径不对,或者文件权限不对。

解决:

  1. 确认文件存在:ls -l /路径/xxx.sql
  2. 确认文件可读:chmod 644 /路径/xxx.sql
  3. 用绝对路径,别用相对路径

报错4:Table already exists

ERROR 1050 (42S01): Table 'xxx' already exists

原因: 表已经存在了。

解决: 两种方法:

  1. 先删表再导入:DROP TABLE xxx;
  2. SQL文件里加 DROP TABLE IF EXISTS xxx;

报错5:Duplicate entry

ERROR 1062 (23000): Duplicate entry 'xxx' for key

原因: 主键重复。

解决:

  1. 先清空表再导入
  2. 或者用 INSERT IGNORE 跳过重复

报错6:字符集乱码

导入后中文变成乱码。

原因: 字符集不对。

解决: 导入前设置字符集:

SET NAMES utf8mb4;
source /路径/xxx.sql;

或者命令行指定:

mysql -u root -p --default-character-set=utf8mb4 数据库名 < xxx.sql

报错7:max_allowed_packet太小

ERROR 2006 (HY000): MySQL server has gone away

原因: SQL文件太大,MySQL接收不了。

解决: 修改my.cnf,加大max_allowed_packet:

[mysqld]
max_allowed_packet = 64M

重启MySQL生效。

导入大文件技巧

方法1:分卷压缩

把大SQL文件拆成小的:

split -b 10M xxx.sql small_

然后逐个导入。

方法2:跳过外键检查

导入时临时关闭外键检查,更快:

SET FOREIGN_KEY_CHECKS = 0;
source /路径/xxx.sql;
SET FOREIGN_KEY_CHECKS = 1;

常见坑

坑1:用错用户名密码

导入时一直提示密码错误。

解决: 确认用户名密码,或者用 mysql -u root -p 交互式输入密码。

坑2:SQL文件不是UTF-8编码

导入后中文乱码。

解决: 用 file 命令查看文件编码:

file -i xxx.sql

坑3:没选对数据库

导入后数据不知道导到哪去了。

解决: 命令行一定要指定数据库名,或者先 USE 数据库名;

总结

导入SQL文件三步走:

  1. 先确认数据库存在
  2. 用正确的字符集导入
  3. 大文件就调大max_allowed_packet

记住: 报错信息一定要看清楚,别瞎试。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:35 

MySQL忘记root密码重置(Linux环境)

前言

忘记MySQL root密码是常见问题,不用慌,本文教你一步步重置。

重置步骤

第一步:停止MySQL服务

systemctl stop mysqld

第二步:以跳过权限模式启动

mysqld_safe --skip-grant-tables &

或者用这个方式:

systemctl set-environment MYSQLD_OPTS="--skip-grant-tables"
systemctl start mysqld

第三步:无密码登录MySQL

mysql -u root

现在不需要密码就能直接进了。

第四步:修改密码

-- 刷新权限
FLUSH PRIVILEGES;

-- 修改密码(MySQL 5.7)
ALTER USER 'root'@'localhost' IDENTIFIED BY '你的新密码';

-- 如果上面不行,用这个
UPDATE mysql.user SET authentication_string=PASSWORD('你的新密码') WHERE User='root' AND Host='localhost';

-- 刷新权限
FLUSH PRIVILEGES;

第五步:退出,正常重启MySQL

exit
systemctl stop mysqld
systemctl start mysqld

第六步:用新密码登录测试

mysql -u root -p

输入新密码,能进去就成功了。

常见坑

坑1:MySQL 8.0和5.7语法不一样

MySQL 8.0 不能用 PASSWORD() 函数了。

解决: 用 ALTER USER 语句。

坑2:skip-grant-tables没生效

启动后还是要密码。

原因: 可能MySQL已经在跑了,新启动的没生效。

解决: 先彻底停掉MySQL:

systemctl stop mysqld
pkill -9 mysqld

再重新启动。

坑3:改完密码忘记FLUSH PRIVILEGES

改完密码直接退出,结果还是不能用新密码登录。

解决: 改完密码一定要执行 FLUSH PRIVILEGES;

坑4:远程登录还是不行

本地改完密码,远程连接还是连不上。

原因: root用户只允许本地登录。

解决: 需要单独授权远程登录:

CREATE USER 'root'@'%' IDENTIFIED BY '密码';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;

总结

六步重置root密码:

  1. 停MySQL
  2. 跳过权限启动
  3. 无密码登录
  4. 改密码
  5. 正常重启
  6. 测试登录

记住: 改完密码一定要 FLUSH PRIVILEGES;

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:34 

MySQL 事务隔离级别

MySQL 事务隔离级别

事务隔离是数据库的重要概念,搞懂4种级别很有必要。

1. 事务的ACID

  • 原子性(Atomicity): 要么全成功,要么全失败
  • 一致性(Consistency): 事务前后数据一致
  • 隔离性(Isolation): 多个事务互不影响
  • 持久性(Durability): 提交后永久保存

2. 4种隔离级别

1)读未提交(Read Uncommitted)

  • 能读到未提交的数据
  • 有脏读、不可重复读、幻读问题
  • 性能最好

2)读提交(Read Committed)

  • 只能读到已提交的数据
  • 解决脏读
  • 有不可重复读、幻读问题
  • Oracle默认级别

3)可重复读(Repeatable Read)

  • 同一个事务里读多次结果一样
  • 解决脏读、不可重复读
  • 有幻读问题
  • MySQL默认级别

4)串行化(Serializable)

  • 事务排队执行
  • 解决所有问题
  • 性能最差

3. 三种问题

脏读:

  • 读到另一个事务未提交的数据
  • 对方回滚了,你读的就是脏数据

不可重复读:

  • 同一个事务里,两次读同一行结果不一样
  • 中间被其他事务修改了

幻读:

  • 同一个事务里,两次查询行数不一样
  • 中间被其他事务插入了

4. 查看和设置

-- 查看当前隔离级别
SELECT @@transaction_isolation;

-- 设置隔离级别
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

5. 实际使用

  • 一般用默认的可重复读就够了
  • 对一致性要求高的用串行化
  • 不要随便改隔离级别

总结

MySQL事务隔离级别要点:

  • 读未提交:性能最好,问题最多
  • 读提交:解决脏读
  • 可重复读:MySQL默认,解决不可重复读
  • 串行化:最安全,性能最差
  • 理解脏读、不可重复读、幻读

做数据库开发,事务隔离一定要懂。


emer 发布于  2026-10-8 07:30 

Redis 常用数据类型

Redis 常用数据类型

Redis 不只是简单的 key-value,有5种常用数据类型,每种适合不同场景。

1. String(字符串)

最基础的类型,存字符串、数字都可以。

# 设置
set name "张三"

# 获取
get name

# 自增
incr age

# 设置过期时间
set token "abc" ex 3600

适用场景: 缓存、计数器、Session。

2. Hash(哈希)

存对象,比如用户信息。

# 设置单个字段
hset user:1 name "张三"

# 获取单个字段
hget user:1 name

# 设置多个字段
hmset user:1 name "张三" age 20 city "北京"

# 获取所有字段
hgetall user:1

适用场景: 存储对象(用户信息、商品信息)。

3. List(列表)

有序列表,可以做消息队列。

# 左侧添加
lpush list "a" "b" "c"

# 右侧添加
rpush list "d"

# 左侧弹出
lpop list

# 查看范围
lrange list 0 -1

适用场景: 消息队列、最新列表。

4. Set(集合)

无序,不重复,做去重。

# 添加
sadd set "a" "b" "c"

# 查看所有
smembers set

# 判断是否存在
sismember set "a"

# 交集
sinter set1 set2

适用场景: 去重、共同好友、标签。

5. ZSet(有序集合)

有序,带分数排序。

# 添加
zadd rank 100 "张三" 90 "李四" 80 "王五"

# 查看排名(从高到低)
zrevrank rank "张三"

# 查看分数
zscore rank "张三"

# 查看排行榜
zrevrange rank 0 9

适用场景: 排行榜、分数排序。

总结

Redis 5种数据类型:

  • String:缓存、计数器
  • Hash:存对象
  • List:消息队列
  • Set:去重、标签
  • ZSet:排行榜

根据场景选对数据类型,用起来才高效。


emer 发布于  2026-10-8 07:29 

PHP 字符串处理函数

PHP 字符串处理函数

字符串处理是 PHP 最常用的操作,这些函数一定要会。

1. 截取字符串

// 截取前n个字符
substr("hello world", 0, 5); // hello

// 中文截取(用mb_substr)
mb_substr("你好世界", 0, 2, "utf-8"); // 你好

2. 替换字符串

//  str_replace 替换
str_replace("world", "PHP", "hello world"); // hello PHP

// 只替换第一次出现
str_replace("a", "b", "aaa", $count);

3. 查找字符串

// 查找位置(找不到返回false)
strpos("hello world", "world"); // 6

// 注意:用 === 0 判断开头
if (strpos($str, "hello") === 0) {
    echo "以hello开头";
}

4. 大小写转换

// 转小写
strtolower("Hello"); // hello

// 转大写
strtoupper("hello"); // HELLO

// 首字母大写
ucfirst("hello"); // Hello

// 每个单词首字母大写
ucwords("hello world"); // Hello World

5. 去除空白

// 去除两边空格
trim("  hello  "); // hello

// 去左边
ltrim("  hello  "); // hello  

// 去右边
rtrim("  hello  "); //   hello

6. 字符串拼接

// 用点拼接
$str = "hello" . " " . "world";

// 多变量拼接
$a = "hello";
$b = "world";
$c = "$a $b"; // hello world

7. 分割和合并

// 分割成数组
$arr = explode(",", "a,b,c"); // ["a", "b", "c"]

// 数组合并成字符串
$str = implode(",", $arr); // a,b,c

8. 常用技巧

1)判断是否包含字符串:

if (strpos($str, "hello") !== false) {
    echo "包含hello";
}

2)反转字符串:

strrev("hello"); // olleh

3)字符串长度:

strlen("hello"); // 5
mb_strlen("你好", "utf-8"); // 2

总结

PHP 字符串处理要点:

  • substr 截取,注意中文用 mb_substr
  • str_replace 替换
  • strpos 查找,用 !== false 判断
  • trim 去空格
  • explode/implode 分割合并
  • 注意中文编码问题,用 mb 开头的函数

写 PHP,字符串函数天天用。


emer 发布于  2026-10-8 07:28 

MySQL 索引优化技巧

MySQL 索引优化技巧

索引是数据库性能的关键,用对了查询快很多。

1. 索引类型

  • 主键索引: 主键自带,唯一且非空
  • 普通索引: 最基本的索引
  • 唯一索引: 字段值不能重复
  • 联合索引: 多个字段组成的索引
  • 全文索引: 全文搜索用

2. 创建索引

-- 普通索引
CREATE INDEX idx_name ON users(name);

-- 唯一索引
CREATE UNIQUE INDEX idx_phone ON users(phone);

-- 联合索引
CREATE INDEX idx_name_age ON users(name, age);

3. 索引失效情况

1)不要在索引字段上做运算:

-- 失效
SELECT * FROM users WHERE age + 1 = 20;

-- 生效
SELECT * FROM users WHERE age = 19;

2)like 左模糊:

-- 失效
SELECT * FROM users WHERE name LIKE '%张';

-- 生效
SELECT * FROM users WHERE name LIKE '张%';

3)联合索引不满足最左前缀:

-- 索引:(name, age)
-- 生效(从name开始)
SELECT * FROM users WHERE name = '张三' AND age = 20;

-- 失效(跳过name直接查age)
SELECT * FROM users WHERE age = 20;

4)用 or 连接:

  • or 两边有一个没索引就全表扫描

4. 优化原则

  • 频繁查询的字段加索引
  • 区分度高的字段适合做索引
  • 不要加太多索引(影响写入性能)
  • 联合索引注意最左前缀
  • 尽量扩展索引,不要新建索引

5. 查看索引

-- 查看表的索引
SHOW INDEX FROM users;

6. 常见问题

  • 索引加了还是慢?检查是不是失效了
  • 查询还是慢?用 EXPLAIN 分析
  • 写入慢?索引太多了

总结

MySQL 索引优化要点:

  • 常用查询字段加索引
  • 注意索引失效情况
  • 联合索引最左前缀
  • 不要加太多索引
  • EXPLAIN 分析执行计划

数据库性能优化,索引是第一步。


emer 发布于  2026-10-8 07:27 

Linux 文件权限详解

Linux 文件权限详解

Linux 权限是基础,搞不懂经常出问题。

1. 查看权限

ls -l

输出:

-rw-r--r-- 1 root root 1000 Oct 8 10:00 test.txt

2. 权限含义

第一位:文件类型

    • 普通文件
  • d 目录
  • l 软链接

后面9位:分3组

  • 第1组:所有者权限
  • 第2组:所属组权限
  • 第3组:其他人权限

3个字母:

  • r 读(4)
  • w 写(2)
  • x 执行(1)

比如 rw-r--r--:

  • 所有者:读写(6)
  • 组:只读(4)
  • 其他人:只读(4)

3. 修改权限 chmod

数字方式:

# 所有者读写执行,组读执行,其他人读执行
chmod 755 test.sh

# 所有人只读
chmod 444 test.txt

字母方式:

# 给所有者加执行权限
chmod u+x test.sh

# 给组加写权限
chmod g+w test.txt

# 去掉其他人的读权限
chmod o-r test.txt

4. 修改所有者 chown

# 修改所有者
chown www:www test.txt

# 递归修改目录
chown -R www:www /www/wwwroot

5. 常用权限

  • 目录:755(所有者读写执行,其他人读执行)
  • 普通文件:644(所有者读写,其他人只读)
  • 脚本文件:755

6. 常见问题

1)网站打不开:

  • 检查目录权限是不是 755
  • 检查文件权限是不是 644
  • 检查所有者是不是 www

2)上传不了文件:

  • 检查目录有没有写权限

3)脚本执行不了:

  • 检查有没有执行权限

总结

Linux 文件权限要点:

  • r=4, w=2, x=1
  • chmod 修改权限
  • chown 修改所有者
  • 目录 755,文件 644
  • 权限不对经常出问题

做运维,权限一定要搞懂。


emer 发布于  2026-10-8 07:26 

Nginx 负载均衡配置

Nginx 负载均衡配置

多台服务器分流,提高网站并发能力,Nginx 负载均衡很常用。

1. 什么是负载均衡

  • 多台服务器做同样的服务
  • Nginx 把请求分发给不同服务器
  • 提高并发能力,一台挂了其他还能用

2. 基础配置

upstream myserver {
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;
    server 127.0.0.1:8082;
}

server {
    listen 80;
    server_name www.example.com;

    location / {
        proxy_pass http://myserver;
    }
}

3. 常用分发策略

1)轮询(默认)

  • 一个接一个轮流分
    upstream myserver {
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;
    }

2)加权轮询

  • 性能好的服务器多分点
    upstream myserver {
    server 127.0.0.1:8080 weight=3;
    server 127.0.0.1:8081 weight=1;
    }

3)ip_hash

  • 同一个IP固定访问同一台
    upstream myserver {
    ip_hash;
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;
    }

4. 健康检查

upstream myserver {
    server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8081 max_fails=3 fail_timeout=30s;
}
  • max_fails:失败几次标记为挂掉
  • fail_timeout:多久后重试

5. 常用参数

upstream myserver {
    # 备用服务器,其他都挂了才用
    server 127.0.0.1:8080 backup;

    # 不参与负载均衡
    server 127.0.0.1:8081 down;
}

6. 注意事项

  • 多台服务器数据要同步(Session、数据库)
  • Session 共享用 Redis
  • 文件上传用共享存储

总结

Nginx 负载均衡要点:

  • upstream 定义服务器组
  • proxy_pass 转发到组
  • 轮询、加权、ip_hash 策略
  • 健康检查自动剔除挂掉的服务
  • 注意 Session 共享

做大并发网站,负载均衡是必备的。


emer 发布于  2026-10-8 07:25