Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >再谈MySQL的optimize table

再谈MySQL的optimize table

作者头像
bisal
发布于 2024-12-19 07:20:17
发布于 2024-12-19 07:20:17
31200
代码可运行
举报
运行总次数:0
代码可运行

MySQL的optimize table是个比较特殊的语句,之前写过这篇《小白学习MySQL - InnoDB支持optimize table?》,对该语句进行了些许讲解。

碰巧看到知乎上的JokerJason老师,写了一篇《MySQL:Optimize Table》的文章,用了一些代码,测试了optimize table对锁、ibd文件等的影响,还是比较直观,可以学习了解。

简介

MySQL 数据库中,OPTIMIZE TABLE 是一个重要的命令,用于优化表的性能和空间利用。通过重新组织表的存储结构,去除碎片,OPTIMIZE TABLE 可以帮助提高查询性能、减少存储空间占用以及减少数据碎片。本文将深入探讨 OPTIMIZE TABLE 的原理、用法、示例以及对 .ibd 文件的影响。

什么情况下使用

使用delete语句删除数据时,delete语句只会将记录的位置或者数据页标记为"可复用",但是数据库磁盘文件的大小不会改变,即表空间不会被回收,此时使用该命令可以释放空间,压缩数据文件。

原理

执行 OPTIMIZE TABLE 命令的过程包括以下几个关键步骤:

  • 创建临时表:MySQL 首先会创建一个与原表结构相同的临时表。
  • 复制数据到临时表:将原表中的数据复制到临时表中。
  • 优化表:在数据复制的过程中,MySQL 会对数据进行整理和重组,去除碎片,提高数据的连续性。
  • 重命名表:当数据复制完成并且表被优化后,MySQL 会删除原表,然后将临时表重命名为原表的名称。

通过这个过程,OPTIMIZE TABLE 可以帮助数据库重新组织表的存储结构,提高查询性能和减少存储空间占用。

示例

  • 创建测试数据,
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
"""
测试optimize table 是否长期锁表
"""
import pymysql


def main():
    conn = pymysql.connect(host="localhost",
                           user="root",
                           password="root",
                           database="test_optimize")
    cursor = conn.cursor()
    sql_create = """
    create table if not exists `person` (
        `id` int primary key auto_increment,
        `name` varchar(255),
        `marks` smallint,
        `create_at` datetime,
        `update_at` datetime
    ) engine=InnoDB default charset=utf8;
    """
    cursor.execute(sql_create)

    sql_insert = """insert into `person` (`name`, `marks`, `create_at`)
    values (%s, %s, now())
    """
    for i in range(195854, 100000000):
        insert_data = (i, 1)
        cursor.execute(sql_insert, insert_data)

        if i % 2 == 0:
            sql_update = """update `person` set create_at = now(), update_at = now() limit 1"""
            cursor.execute(sql_update)
        if i%999 == 0:
            print(i)

        i+=1
    conn.commit()
    cursor.close()
    conn.close()


if __name__ == '__main__':
    main()

开启三个线程执行update操作,在MySQL客户端执行optimize table 命令,查看update是否有明显延时。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import concurrent
import datetime
import time
from concurrent.futures import ThreadPoolExecutor

import pymysql


def main():
    conn = pymysql.connect(host="localhost",
                           user="root",
                           password="root",
                           database="test_optimize")
    cursor = conn.cursor()

    for i in range(0, 10000000):
        if i % 2 == 0:
            sql_update = """update `person` set create_at = now(), update_at = now() limit 1"""
            cursor.execute(sql_update)
            conn.commit()
        print("{}, time: {}".format(i, datetime.datetime.now()))
        i += 1

    cursor.close()
    conn.close()


if __name__ == '__main__':
    # 使用ThreadPoolExecutor创建一个线程池
    with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
        # 提交任务到线程池
        futures = [executor.submit(main) for _ in range(3)]

        # 异步执行任务,并在每个任务完成后立即处理结果
        for future in concurrent.futures.as_completed(futures):
            result = future.result()
            print(result)

执行脚本,并在MySQL客户端执行optimize table person。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
MySQL root@(none):test_optimize> optimize table person
+----------------------+----------+----------+-------------------------------------------------------------------+
| Table                | Op       | Msg_type | Msg_text                                                          |
+----------------------+----------+----------+-------------------------------------------------------------------+
| test_optimize.person | optimize | note     | Table does not support optimize, doing recreate + analyze instead |
| test_optimize.person | optimize | status   | OK                                                                |
+----------------------+----------+----------+-------------------------------------------------------------------+

2 rows in set
Time: 8.854s

这里执行optimize table时间大概有9s,如果整个过程加锁,则update操作会有明显的延迟。这里与MySQL的版本有关系,5.6及以下版本,的确会在整个过程加锁。

更详细的信息可以通过MySQL官网查看,

https://dev.mysql.com/doc/refman/8.3/en/optimize-table.html

查看ibd文件的变化

执行前,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
root@fresh-vdh510:/var/lib/mysql/test_optimize# du -sh person.ibd 
49M person.ibd

执行后,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
root@fresh-vdh510:/var/lib/mysql/test_optimize# du -sh person.ibd 
15M person.ibd

ibd文件

MySQL中的.ibd文件是InnoDB存储引擎用来存储表数据和索引的物理文件。每个使用InnoDB存储引擎的表,如果启用了独立表空间(每表一个文件),则会有一个对应的.ibd文件来存储该表的所有数据和所有的索引结构。

具体来说,.ibd文件包含以下内容:

  • 表的数据行记录
  • 表的所有索引,包括主键索引和其他辅助索引
  • 用于实现多版本并发控制(MVCC)的信息,这是InnoDB为了支持事务处理和高并发场景而采用的技术。

在InnoDB中,表可以被组织为不同的表空间类型:

  • 系统表空间:所有表共享一个大的表空间文件(ibdata1等)。
  • 独立表空间:每个表及其索引分别存储在各自的.ibd文件中。

管理.ibd文件的方法可能包括:

  • 备份与恢复:直接复制.ibd文件作为备份的一种方式,但在恢复时需要注意一致性问题,通常建议使用数据库级的备份和恢复方法。
  • 表空间操作:如收缩表空间、优化表碎片等高级管理任务。

需要注意的是,在进行任何涉及.ibd文件的操作时,应当确保数据库服务已停止或者相关表处于只读状态,以防止数据不一致或损坏。同时,直接操作.ibd文件而不通过MySQL服务器API可能会导致数据丢失或不可预测的行为。

也就是说在执行optimize的时候,因为其本质是创建了临时表,所以会生成一个新的ibd文件,在临时表覆盖原表之后,原ibd文件也会被删除。

注意事项

使用OPTIMIZE TABLE 作用于InnoDB和MYISM引擎时(只有这两个引擎可用),在MySQL5.7和MySQL8.0及以上版本的时候,因为数据库支持online DDL,可以并发执行。所以执行这个语句的时候,会有一小段时间锁表,之后DML语句是可以执行的。

使用OPTIMIZE TABLE 需要创建一个临时表,所以需要在此之前保证磁盘容量足够。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-12-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 bisal的个人杂货铺 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
小白学习MySQL - InnoDB支持optimize table?
MySQL数据库中进行表空间整理,可以用的一种操作就是optimize table,
bisal
2021/09/06
2.1K0
pymysql ︱mysql的基本操作与dbutils+PooledDB使用
python3.6 使用 pymysql 连接 Mysql 数据库及 简单的增删改查操作
悟乙己
2021/12/07
5.1K0
pymysql ︱mysql的基本操作与dbutils+PooledDB使用
MySQL 怼了架构师关于 optimize table 需求 与 为什么反对 optimize table
2024年1月某些星象的原因,导致我个人的星盘在1月大概率要和某些人要有不愉快。这不就来了,在一次关于mysql 数据库数据表清理后,关于optimize table 的问题上,我毫无悬念的和架构师们进行了一次非常不nice 的沟通。
AustinDatabases
2024/01/14
7170
MySQL  怼了架构师关于 optimize table 需求 与 为什么反对 optimize table
MySQL数据库的高级使用
推荐文章: Liunx系列: 1、Linux基础命令 2、Linux进阶命令 任务编程系列: 1、多任务编程 - 1 2、多任务编程 - 2 前端技术: 1、JavaScript
用户9399690
2022/01/20
1.9K0
MySQL数据库的高级使用
MYSQL 5.7 到底 OPTIMIZE Table 塞不塞 DML
所以借此篇,1来证明optimize table 不阻塞DML 2 表示对好友lmongo的感谢, 有一个能指出你错误,并大胆友善说出来的人,不多,要感谢。
AustinDatabases
2020/03/31
3.4K0
MYSQL  5.7 到底 OPTIMIZE Table 塞不塞  DML
【呕心总结】python如何与mysql实现交互及常用sql语句
9 月初,我对 python 爬虫 燃起兴趣,但爬取到的数据多通道实时同步读写用文件并不方便,于是开始用起mysql。这篇笔记,我将整理近一个月的实战中最常用到的 mysql 语句,同时也将涉及到如何在python3中与 mysql 实现数据交换。
刘娟娟PRESSone
2019/10/25
3.1K0
【呕心总结】python如何与mysql实现交互及常用sql语句
Python 操作 MySQL
直接使用pip安装 pip install pymysql win64上直接在cmd中执行
AnRFDev
2021/02/01
7450
Python MySQL数据库交互
可能默认的源安装第三库会有点慢,可以配置一下其他的镜像源。Pip安装第三方库网速慢(解决方案)
忆想不到的晖
2021/04/04
1.1K0
Python MySQL数据库交互
python3基础:操作mysql数据库
基本操作: 登陆:mysql -uroot -h127.0.0.1 -P3306 -p mysql -uroot -p(本机不用写host) 退出mysql:ctrl+z+回车,或者exit 端口号默认是3306,但是可以通过安装目录下的配置文件修改。
全栈程序员站长
2022/09/05
1.1K0
MySQL数据库4Python操作mysql、索引、慢查询日志
pymysql是通过python操作mysql的模块,需要先安装,方法:pip install pymysql
GH
2019/12/12
2K0
MYSQL 毛病那么多,optimize table 为什么做不了
MySQL 在数据增长中,会遇到一个问题数据在清理后,无法将数据表空间回收,大多数的人员在处理这个问题的时候,可以通过optimize table 的方案来解决.
AustinDatabases
2024/04/18
4610
MYSQL  毛病那么多,optimize table 为什么做不了
第10期:选择合适的表空间
MySQL 表空间可分为共享表空间和单表空间;其中共享表空间又可分为系统表空间和通用表空间。
爱可生开源社区
2020/08/11
6860
第10期:选择合适的表空间
python_day11のPython操
pymysql是Python中操作MySQL的模块,其使用方法和python2.7的MySQLdb几乎相同。
py3study
2020/01/13
4980
optimize 回收表空间的一些说明
线上服务器,有张大表需要用pt-archiver根据时间划分归档大量数据到另一个新表中。原先200G的表,在归档完成后,du -hs 显示依然是200G的大小,删除了大量的行记录但是实际上空间是不会释放的。
保持热爱奔赴山海
2019/09/17
9800
Python3 MySQL 数据库连接 - PyMySQL 驱动
PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2 中则使用 mysqldb
十二惊惶
2024/02/28
5450
【详解】Python3.6连接MySQL
在现代Web开发和数据处理中,Python与数据库的交互是必不可少的一部分。MySQL作为最流行的开源关系型数据库管理系统之一,与Python的结合可以实现高效的数据存取操作。本文将介绍如何在Python 3.6环境中通过​​pymysql​​库连接到MySQL数据库,并执行基本的SQL查询。
大盘鸡拌面
2025/04/05
1580
MySQL至TiDB复制延迟监控
因生产环境mysql中有较多复杂sql且运行效率低,因此采用tidb作为生产环境的从库进行部分慢sql及报表的读写分离。其中MySQL至TIDB采用Syncer工具同步。
俊才
2019/08/07
1.2K0
MySQL至TiDB复制延迟监控
[MYSQL] mysql 参数lower_case_table_names的修改
该参数默认是0, 即区分大小写. 但现在又想要不区分大小写了. 也就是想设置其值为1. 首先我们要确保数据库里面的表均为小写, 我们可以通过如下sql查询
大大刺猬
2024/09/11
1.3K0
[MYSQL] mysql 参数lower_case_table_names的修改
[MYSQL] mysql新版本(8.0.38)引入新BUG. (建议不要使用Mysql最新版)(附 临时处理方法)
看到percona发了篇Do Not Upgrade to Any Version of MySQL After 8.0.37. 说是mysql新版本有BUG.
大大刺猬
2024/07/12
70115
[MYSQL] mysql新版本(8.0.38)引入新BUG. (建议不要使用Mysql最新版)(附 临时处理方法)
基于Python的mysql与excel互相转换
getConn函数获取mysql连接,第1个参数database为要连接的数据库。 mysql2excel函数完成主要转换功能,第1个参数database为要连接的数据库,第2个参数为要转换的数据表,第3个参数为要保存的excel文件名。 在执行cursor.execute后,利用data_list = cursor.fetchall()获取数据库中所有数据,利用cursor.description获取函数中字段的相关信息, 字段的相关信息的数据类型为元组,其中第1个为字段名。 利用xlwt.Workbook()方法实例化对象赋值给excel变量,利用excel.add_sheet()方法获取新的表格,利用sheet.write()往excel文件中写入数据。
潇洒坤
2018/09/10
1.4K0
相关推荐
小白学习MySQL - InnoDB支持optimize table?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验