MySQL常用操作

MySQL常用示例及慢查询总结

在日常工作中,大部分项目采用的是MySQL作为数据库支撑,下面总结日常需要用到的一些比较实用的查询,后续会不断补充,感兴趣的小伙伴可以留言好用的查询语句,与君共勉。

常用示例

1. 查询数据库所有表明和对应的字段名称

select table_name, column_name from information_schema.columns where table_schema='db_name' and table_name in (select table_name from information_schema.tables where table_schema='db_name') ;

2.查询表名、表注释

SELECT table_name 表名, table_comment 表注释 FROM information_schema.TABLES WHERE table_schema = 'db_name'

3.查看当前表字段注释

select COLUMN_NAME 字段名, column_comment 字段说明, column_type 字段类型, column_key 约束 from information_schema.columns where table_schema = '数据库名' and table_name = 'table_name' ;

或者:

show full columns from 表名;

4.查看表生成的DDL

show create table table_name;

5.创建表

create table t_user( ID INT(19) primary key auto_increment comment '主键', NAME VARCHAR(300) comment '姓名', CREATE_TIME date comment '创建时间' )comment = '用户信息表';

6.修改表字段

alter table t_user comment = '修改后的表注释信息(用户信息表)';

7. 关联查询数据只在左表存在数据的情况

在这里插入图片描述
select tcc.customer_id from TABLE_A tcc left join TABLE_B tcra on tcc.customer_id = tcra.customer_id and tcra.customer_id is null;

8. 关联查询数据不在内表存在数据的情况

在这里插入图片描述

select tmc.id from TABLE_A ta where id not in (select customer_id from TABLE_B tb where tb.status = 0 group by tb.customer_id) and ta.status = 1 order by ta.create_time desc ;

9.从一个表更新字段值到另一个表字段

update tableA as a join tableB as b on a.no=b.no set a.name=b.name where a.status=1

10.查询表字段及对应注释

SELECT TABLE_NAME 表名, COLUMN_NAME 列名, COLUMN_TYPE 数据类型, COLUMN_KEY 主键, IF(IS_NULLABLE='NO','是','否') AS '必填', COLUMN_COMMENT 注释 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='db_name' AND table_name in ('table_name_1','table_name_2','table_name_3');

11. 删除操作

delete 语句

delete from table_name;

12.查询表空间大小
 select concat(round(sum(DATA_LENGTH/1024/1024),2),'M') as table_size
 from information_schema.tables  where table_schema='db_name' AND table_name='table_name';

表字段加索引总大小

SELECT table_name, table_schema, round(((data_length + index_length) / 1024 / 1024), 2) MB FROM information_schema.TABLES WHERE table_schema = "database_name" AND table_name = "table_name";
13.查询所有表行数、表空间大小
SELECT TABLE_NAME,TABLE_ROWS,DATA_LENGTH/1024/1024 "DATA_LENGTH",CREATE_TIME,TABLE_COLLATION FROM
 INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'rdsdb' ORDER BY TABLE_ROWS DESC
14.MySQL innodb引擎空间优化语句

optimize table table_name;

1.重新组织表:使用OPTIMIZE TABLE语句可以重新组织表以减少碎片。例如,执行OPTIMIZE TABLE table_name;将重建指定表的索引和数据,从而减少碎片。
2.重建索引:使用ALTER TABLE语句可以重建表的索引。例如,执行ALTER TABLE table_name ENGINE=InnoDB;会重建表的所有索引,同时修复碎片问题。
3.压缩表空间:使用OPTIMIZE TABLE语句时添加OPTIMIZE TABLE table_name INPLACE;选项可以在不重新创建表的情况下压缩表的空间,减少碎片。
4.调整InnoDB参数:通过调整InnoDB的相关参数可以改善表空间的碎片情况。例如,适当调整innodb_fill_factor和innodb_page_size参数可以控制InnoDB存储页的填充程度,从而减少碎片。

上述示例中:
1、DELETE属于数据库DML操作语言,只删除数据不删除表的结构,会走事务,执行时会触发trigger;

2、在 InnoDB 中,DELETE其实并不会真的把数据删除,mysql 实际上只是给删除的数据打了个标记为已删除,因此 delete 删除表中的数据时,表文件在磁盘上所占空间不会变小,存储空间不会被释放,只是把删除的数据行设置为不可见。 虽然未释放磁盘空间,但是下次插入数据的时候,仍然可以重用这部分空间(重用 → 覆盖)。

3、 DELETE执行时,会先将所删除数据缓存到rollback segement中,事务commit之后生效;

4、 delete from table_name删除表的全部数据,对于MyISAM 会立刻释放磁盘空间,InnoDB 不会释放磁盘空间;

5、对于delete from table_name where xxx 带条件的删除, 不管是InnoDB还是MyISAM都不会释放磁盘空间;

6、 delete操作以后使用 optimize table table_name 会立刻释放磁盘空间。不管是InnoDB还是MyISAM 。所以要想达到释放磁盘空间的目的,delete以后执行optimize table 操作。

7、delete 操作是一行一行执行删除的,并且同时将该行的的删除操作日志记录在redo和undo表空间中以便进行回滚(rollback)和重做操作,生成的大量日志也会占用磁盘空间。

15.truncate 语句

truncate table table_name;

1、truncate:属于数据库DDL定义语言,不走事务,原数据不放到 rollback segment 中,操作不触发 trigger。

执行后立即生效,无法找回 执行后立即生效,无法找回 执行后立即生效,无法找回

2、 truncate table table_name 立刻释放磁盘空间 ,不管是 InnoDB和MyISAM 。truncate table其实有点类似于drop table 然后creat,只不过这个create table 的过程做了优化,比如表结构文件之前已经有了等等。所以速度上应该是接近drop table的速度;

3、truncate能够快速清空一个表。并且重置auto_increment的值。

但对于不同的类型存储引擎需要注意的地方是:

对于MyISAM,truncate会重置auto_increment(自增序列)的值为1。而delete后表仍然保持auto_increment。 对于InnoDB,truncate会重置auto_increment的值为1。delete后表仍然保持auto_increment。但是在做delete整个表之后重启MySQL的话,则重启后的auto_increment会被置为1。 也就是说,InnoDB的表本身是无法持久保存auto_increment。delete表之后auto_increment仍然保存在内存,但是重启后就丢失了,只能从1开始。实质上重启后的auto_increment会从 SELECT 1+MAX(ai_col) FROM t 开始。

4、清库脚本

select CONCAT('truncate TABLE ',table_schema,'.',TABLE_NAME, ';') from INFORMATION_SCHEMA.TABLES where  table_schema in ('数据库1','数据库2');`
16.drop 语句

drop table table_name;
1、drop:属于数据库DDL定义语言,同truncate;

执行后立即生效,无法找回 执行后立即生效,无法找回 执行后立即生效,无法找回

2、 drop table table_name 立刻释放磁盘空间 ,不管是 InnoDB 和 MyISAM; drop 语句将删除表的结构被依赖的约束(constrain)、触发器(trigger)、索引(index); 依赖于该表的存储过程/函数将保留,但是变为 invalid 状态。

17.deleted、truncate、drop总结
1.delete不会直接删除数据,但在optimize执行之后会释放delete的空间;
2.truncate会清空表内容;
3.drop清空表内容并且删除表;
18.在线添加索引(减少锁表的情况,性能影响较小)

ALTER TABLE table_name ADD INDEX index_name (column_name), ALGORITHM=INPLACE, LOCK=NONE;
MySQL 8 版本以后支持在线DDL操作
删除索引
ALTER TABLE 表名 DROP INDEX 索引名称;

19.mysql分区表创建,索引添加及验证(5.7.30 InnoDB存储引擎)
创建分区表
CREATE TABLE test (
  id INT,
  data VARCHAR(255),
  created_at DATE
) PARTITION BY RANGE(EXTRACT(MONTH FROM created_at)) (
  PARTITION p01 VALUES LESS THAN (2),
  PARTITION p02 VALUES LESS THAN (3),
  PARTITION p03 VALUES LESS THAN (4),
  PARTITION p04 VALUES LESS THAN (5),
  PARTITION p05 VALUES LESS THAN (6),
  PARTITION p06 VALUES LESS THAN (7),
  PARTITION p07 VALUES LESS THAN (8),
  PARTITION p08 VALUES LESS THAN (9),
  PARTITION p09 VALUES LESS THAN (10),
  PARTITION p10 VALUES LESS THAN (11),
  PARTITION p11 VALUES LESS THAN (12),
  PARTITION p12 VALUES LESS THAN (13)
);

删除分区表
drop table test;

插入分区表
INSERT INTO test PARTITION (p01) (id, data, created_at)
VALUES (1, 'data 1', '2023-01-20');
INSERT INTO test PARTITION (p02) (id, data, created_at)
VALUES (2, 'data 2', '2023-02-20');
INSERT INTO test PARTITION (p02) (id, data, created_at)
VALUES (22, 'data 22', '2023-02-22');
INSERT INTO test PARTITION (p03) (id, data, created_at)
VALUES (3, 'data 3', '2023-03-22');
INSERT INTO test PARTITION (p12) (id, data, created_at)
VALUES (12, 'data 12', '2023-12-01');

分区表数据查询
SELECT * FROM test;
SELECT * FROM test PARTITION (p02);
SELECT * FROM test PARTITION (p12);
SELECT * FROM test PARTITION (p11) where created_at > '2022-01-21';

INSERT INTO test PARTITION (p02) (id, data, created_at)
VALUES (12, 'data 12', '2021-01-20');

分区表数据更新
UPDATE test PARTITION (p02) SET data = '小朋友' WHERE id = 22;
UPDATE test PARTITION (p03) SET data = '小朋友' WHERE id = 22;

删除分区表数据
DELETE FROM test PARTITION (p01);

添加索引(非锁表建议方式:实际生产验证,50w条左右数据的表正常添加,500w条数据的表添加,依旧锁表,
导致交易入库报错,并发不高,一分钟50笔交易左右)
ALTER TABLE test ADD INDEX indx_created_at(created_at), ALGORITHM=INPLACE, LOCK=NONE; 

分区表不支持单分区 truncate,删除的空间可能无法复用
1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server 
version for the right syntax to use near 'PARTITION (p12)' at line 1

分区表重建,锁表
ALTER TABLE your_table_name REORGANIZE PARTITION partition_name1 INTO (PARTITION partition_name2 ...);

据了解,InnoDB存储引擎在mysql8.0及以上版本支持在线DDL执行,支持不锁表;
20.对于MySQL 5.7.30版本的InnoDB存储引擎,并且希望实现在线DDL操作而不锁定表

pt-online-schema-change是Percona Toolkit的一个工具,它提供了一种在MySQL上执行在线DDL操作的方法,而不会长时间锁定表。
它的工作原理是创建一个与原始表结构相同但具有不同名称的辅助表,在后台以低优先级方式复制并同步数据。然后逐步将修改应用到辅助表上,直至完成DDL操作,最后再将表名切换回原始表,从而实现无锁的DDL操作。

pt-online-schema-change可以通过以下步骤来执行在线DDL操作:

1.安装和配置Percona Toolkit工具包。
2.使用pt-online-schema-change命令指定要进行DDL操作的表、要添加的索引等参数。
pt-online-schema-change将创建一个与原表类似的仿制表,并开始以低优先级复制和同步数据。
在后台逐步应用DDL操作到仿制表上,这个过程可能需要一些时间,具体取决于表的大小和系统性能。
3.当DDL操作完成时,pt-online-schema-change会将原始表重命名为备份表,并将仿制表重命名为原始表。
最后,完成DDL操作并删除备份表。

需要注意的是,使用pt-online-schema-change进行在线DDL操作依然会对系统性能产生一定影响,但它会尽量减少锁表时间,并且不会阻塞其他的读写操作。
请确保在使用pt-online-schema-change之前进行充分的测试,并备份重要的数据。

21.BLOB大字段转UTF8文本查询
SELECT CONVERT(blob_column_name USING utf8) AS readable_text
FROM table_name WHERE condition;

慢查询优化

1.后台系统统计数目
SLOW_SQL【报警】
     当前时间: 2020-07-24 09:38:01
     数据库地址: xxx.xx.xxx.xx
     数据库端口: 3306
     数据库名: db_name
     业务方向: xxxxxxxx
     执行时长: 大于 10 秒
     执行用户:db_name_rw
     执行地址: xx.xx.xx.xx
     总计慢sql: 1
     执行SQL:
    SELECT count(1) FROM t_table_record t
WHERE t.effect= 0
AND t.date >= 1585670400
AND 1595520000 >= t.date
AND EXISTS(
SELECT 1 FROM t_table_cust c WHERE c.effect= 0 AND t.cust_no = c.cust_no AND c.sys_id = 1
) 
执行explain分析结果如下:

在这里插入图片描述
在这里插入图片描述

分析explain执行结果:
优化前扫描行数

在这里插入图片描述

分析报告:
摘要内容示例
建议使用 AS 关键字显示声明一个别名在列或表别名(如"tbl AS alias")中, 明确使用 AS 关键字比隐含别名(如"tbl alias")更易懂。select name from tbl t1 where id < 1000
MySQL 对子查询的优化效果不佳MySQL 将外部查询中的每一行作为依赖子查询执行子查询。 这是导致严重性能问题的常见原因。这可能会在 MySQL 5.6 版本中得到改善, 但对于5.1及更早版本, 建议将该类查询分别重写为 JOIN 或 LEFT OUTER JOIN。select col1,col2,col3 from table1 where col2 in(select col from table2)
为db_name库的t_table_cust表添加索引为列effect添加索引;为列system_id添加索引ALTER TABLE db_name.t_table_cust add index idx_effect_system_id (effect,system_id) ;
为db_name库的t_table_record表添加索引为列effect添加索引;为列date添加索引ALTER TABLE fi_dfm.t_table_record add index idx_effect_date (effect,date) ;
指定了 WHERE 条件或非 MyISAM 引擎时使用 COUNT(*) 操作性能不佳COUNT() 的作用是统计表行数,COUNT(COL) 的作用是统计指定列非 NULL 的行数。MyISAM 表对于 COUNT() 统计全表行数进行了特殊的优化,通常情况下非常快。但对于非 MyISAM 表或指定了某些 WHERE 条件,COUNT(*) 操作需要扫描大量的行才能获取精确的结果,性能也因此不佳。有时候某些业务场景并不需要完全精确的 COUNT 值,此时可以用近似值来代替。EXPLAIN 出来的优化器估算的行数就是一个不错的近似值,执行 EXPLAIN 并不需要真正去执行查询,所以成本很低。SELECT c3, COUNT(*) AS accounts FROM tab where c2 < 10000 GROUP BY c3 ORDER BY num
不建议使用 COUNT(col) 或 COUNT(常量)不要使用 COUNT(col) 或 COUNT(常量) 来替代 COUNT(), COUNT() 是 SQL92 定义的标准统计行数的方法,跟数据无关,跟 NULL 和非 NULL 也无关。SELECT COUNT(1) FROM tbl;
分析逻辑完成,添加索引:
ALTER TABLE t_table_record add INDEX  i_cust_no (`cust_no `) USING BTREE;
优化完成,执行explain分析结果如下:

在这里插入图片描述

优化后扫描行数

在这里插入图片描述

MySQL 字符编码修改

1. UTF8 和 UTF8MB4 字符集介绍

字符(Character)是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。字符集(Character set)是多个字符的集合。

MySQL 中字符集可以作用于四个级别,分别是:服务器级别、数据库级别、表级别、列级别。服务器级别的比较规则由 character_set_server 参数控制,如果创建数据库、表、列时没有显式的指定字符集,则会继承上一级的字符集。

MySQL 5.7 及之前版本默认的字符集是 latin1MySQL 8.0 版本默认的字符集是 utf8mb4 。不过使用 latin1 容易导致乱码,所以还是 utf8utf8mb4 用途最广泛。utf8 其实是 utf8mb3 的别名,只使用 1~3 个字节表示字符。utf8mb4 使用 1~4 个字节表示字符,能够存储更多的 emoji 表情及任何新增的 Unicode 字符。utf8mb4 兼容 utf8 ,且比 utf8 能表示更多的字符,是 utf8 字符集的超集。所以现在一些新的业务建议将数据库的字符集设置为 utf8mb4 ,特别是有表情存储需求时。

2. 修改字符集方法

目前的互联网业务对 emoji 表情存储的需求越来越多,比如昵称、评论内容等都要支持表情符号,这个时候如果数据库字段用的是 utf8 字符集,则会报如下错误:
java.sql.SQLException: Incorrect string value: ‘\xF0\x9F\x92\x95\xF0\x9F…’ for column………

为了业务需求,我们需要将数据库字符集改为 utf8mb4,好在 utf8mb4 utf8 的超集,除了将编码改为 utf8mb4 外不需要做其他转换。这里简单讲下修改方法。
系统参数修改

首先应该修改系统字符集参数,这样以后创建的库表默认字符集就是 utf8mb4 了。找到配置文件,添加或修改以下参数:

vi /etc/my.cnf

[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
skip-character-set-client-handshake
#忽略应用连接自己设置的字符编码,保持与全局设置一致
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
1234567891011

修改数据库字符集

对于已经创建的数据库,如果原来是 utf8 字符集,则可以这么修改:

# 设置数据库字符集编码
ALTER DATABASE `dbname` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

# 示例
mysql> show create database testdb;
+----------+-----------------------------------------------------------------+
| Database | Create Database                                                 |
+----------+-----------------------------------------------------------------+
| testdb   | CREATE DATABASE `testdb` /*!40100 DEFAULT CHARACTER SET utf8 */ |
+----------+-----------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> alter database `testdb` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
Query OK, 1 row affected (0.01 sec)

mysql> show create database testdb;
+----------+--------------------------------------------------------------------+
| Database | Create Database                                                    |
+----------+--------------------------------------------------------------------+
| testdb   | CREATE DATABASE `testdb` /*!40100 DEFAULT CHARACTER SET utf8mb4 */ |
+----------+--------------------------------------------------------------------+
1 row in set (0.00 sec)
12345678910111213141516171819202122

修改表及字段字符集

同样的,对于已经创建的表,修改全局及数据库的字符集并不会影响原表及字段的字符集。原有的 utf8 表可以采用如下方法修改:

# 修改表字符集
alter table `tb_name` default character set utf8mb4;

# 修改某字段字符集
alter table `tb_name` modify col_name varchar(20) character set utf8mb4;

# 同时修改表及字段字符集
alter table `tb_name` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

# 如果某个库里面表比较多 可以拼接出要执行的批量修改语句
SELECT
	CONCAT( 'ALTER TABLE ', TABLE_NAME, ' CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;' ) 
FROM
	information_schema.`TABLES` 
WHERE
	TABLE_SCHEMA = 'testdb';
9262567891012141516
3. 一些建议

看起来修改方法挺简单,不过对于生产环境还是要格外小心。特别是修改字段字符集时,会加锁,阻止写操作,对于大表执行下来也是很慢的,可能对线上业务造成影响。

如果你的数据库比较小,用以上方法应该问题不大。对于线上环境,若要修改字符集,一定要做好评估,最好可以在业务低峰期停机修改,修改前一定要先备份。若无停机时间,可以考虑先在备库修改,然后再主备切换,不过这样做会更麻烦。

有条件的话也可以再准备一个空实例,先导入表结构,改成 utf8mb4 字符集后再导入数据。这也是一种方法,不过也可能需要停机切换。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值