MySQL 怼了架构师关于 optimize table 需求 与 为什么反对 optimize table

这开头还是介绍一下群,如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, Oceanbase, Sql Server等有问题,有需求都可以加群群内,可以解决你的问题。加群请联系 liuaustin3 ,(共1830人左右 1 + 2 + 3 + 4 +5) 4群(360+ 关闭自由申请,新入群的将默认分配达到5群),另欢迎 OpenGauss 的技术人员加入。

588c08fd7e740619c41749a05c848410.png

2024年1月某些星象的原因,导致我个人的星盘在1月大概率要和某些人要有不愉快。这不就来了,在一次关于mysql 数据库数据表清理后,关于optimize table 的问题上,我毫无悬念的和架构师们进行了一次非常不nice 的沟通。

随意就有了此篇的文章,因为我这个人比较的要通过实际的情况来说明问题,而不是用权威来压制,那样没有品。事情简单的说一下,几十个库,几百张表,要进行数据的清理,这没有问题,我们会使用自动的手段来进行,而后面一个架构师提出,希望能对表进行optimize table 的操作,并且提出这样的好处多多。 

但是,但是,但是,说话办事就怕光站在自己的角度来说问题,我对此要求是拒绝的,并且我拿出了 PG SQL SERVER ORACLE 甚至 IBM DB2 的一些理论对于对方无礼的需求进行驳斥,因为这个架构师提出,optimize table 很快,MYSQL8 有新功能,大致的意思我翻译一下,optimize table 的任何过程中,不会对表产生影响,产生锁,产生业务影响。因为我们是 7*24小时的业务,所以DB 对于表在一些操作的中,是非常忌讳,产生TABLE LOCK 并且是无预估的长时间的表不可用的情况。 

那么我们来看看到底MYSQL8  是否如这个架构师讲的,很快不会对业务有什么影响。

我们使用一个,说新不新 ,说旧不旧的MySQL数据库版本,8.031 来验证MYSQL8 对这个optimize table 并没有多少改进。

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.31    |
+-----------+
1 row in set (0.00 sec)

1 我们验证当数据库有事务在操作数据表时,是否会对optimize table 的命令产生影响,也就是之间的操作是互斥的。结果可以参见下图,必然是互相影响。optimize table 被  一个对表进行数据插入的事务卡主了。

e061f592359c2c9f190b67cb9aecf0f9.png

mysql> select * from schema_table_lock_waits\G
*************************** 1. row ***************************
               object_schema: test
                 object_name: test
           waiting_thread_id: 71
                 waiting_pid: 7
             waiting_account: db_admin@mysql830
           waiting_lock_type: SHARED_NO_READ_WRITE
       waiting_lock_duration: TRANSACTION
               waiting_query: optimize table test
          waiting_query_secs: 1245
 waiting_query_rows_affected: 0
 waiting_query_rows_examined: 0
          blocking_thread_id: 81
                blocking_pid: 8
            blocking_account: db_admin@mysql830
          blocking_lock_type: SHARED_WRITE
      blocking_lock_duration: TRANSACTION
     sql_kill_blocking_query: KILL QUERY 8
sql_kill_blocking_connection: KILL 8
1 row in set (0.01 sec)

同时在genernal log 中跟踪相关操作,这里可以看到操作本身是没有分解操作的,原子性的语句进行传递,如有从库也会进行传递到从库执行。

548b1a75d26590fdd15d3fe8bbcc61e7.png

在MySQL 8 中越来越智能的sys 库中的lock_waits 视图可以清晰的看到,optimize table 到底上了什么锁,,那么这个锁是什么这个锁属于metadata_locks 中的其中一种

INTENTION_EXCLUSIVE, 

SHARED, 

SHARED_HIGH_PRIO, 

SHARED_READ, 

SHARED_WRITE, 

SHARED_UPGRADABLE,

 SHARED_NO_WRITE, 

SHARED_NO_READ_WRITE, 

EXCLUSIVE

那么我们在执行了这个操作后,出现什么情况,从下面的图中可以清晰的看到,我们在一个就只有1行的数据表中,进行了optimize table 的操作,然后我们毫无悬念的发现在执行完毕这个命令后,表的文件的日期更新了,这里可以证明,在8.031 版本的mysql 中与我们之前MYSQL 的版本对于optimize table 的原理毫无实质的变化。

+-----------+----------+----------+-------------------------------------------------------------------+
| Table     | Op       | Msg_type | Msg_text                                                          |
+-----------+----------+----------+-------------------------------------------------------------------+
| test.test | optimize | note     | Table does not support optimize, doing recreate + analyze instead |
| test.test | optimize | status   | OK                                                                |
+-----------+----------+----------+-------------------------------------------------------------------+
mysql> select * from test;
+----+--------------+--------------+
| id | name         | title        |
+----+--------------+--------------+
|  1 | å°æŽ       | å°æŽ       |
+----+--------------+--------------+
1 row in set (0.00 sec)
[mysql@mysql830 test]$ ll -ah
total 3.4G
drwxr-x---  2 mysql mysql  190 Nov 17 12:58 .
drwxr-x--- 11 mysql mysql 4.0K Nov 17 12:38 ..
-rw-r-----  1 mysql mysql 112K Apr 14  2023 app_user_1000.ibd
-rw-r-----  1 mysql mysql 3.4G Apr 14  2023 app_user.ibd
-rw-r-----  1 mysql mysql 112K Nov 17 05:04 bm_card_account_recharge_
-rw-r-----  1 mysql mysql 144K Apr 15  2023 orders_copy.ibd
-rw-r-----  1 mysql mysql 160K Apr 15  2023 orders.ibd
-rw-r-----  1 mysql mysql 128K Apr 14  2023 payments.ibd
-rw-r-----  1 mysql mysql 112K Nov 17 12:35 read_table.ibd
-rw-r-----  1 mysql mysql 112K Nov 17 12:58 test.ibd
[mysql@mysql830 test]$ ll -ah
total 3.4G
drwxr-x---  2 mysql mysql  190 Nov 17 13:32 .
drwxr-x--- 11 mysql mysql 4.0K Nov 17 12:38 ..
-rw-r-----  1 mysql mysql 112K Apr 14  2023 app_user_1000.ibd
-rw-r-----  1 mysql mysql 3.4G Apr 14  2023 app_user.ibd
-rw-r-----  1 mysql mysql 112K Nov 17 05:04 bm_card_account_recharge_ext.ibd
-rw-r-----  1 mysql mysql 144K Apr 15  2023 orders_copy.ibd
-rw-r-----  1 mysql mysql 160K Apr 15  2023 orders.ibd
-rw-r-----  1 mysql mysql 128K Apr 14  2023 payments.ibd
-rw-r-----  1 mysql mysql 112K Nov 17 12:35 read_table.ibd
-rw-r-----  1 mysql mysql 112K Nov 17 13:32 test.ibd

当然同样的命令还有  alter table tablename force;和 alter table tablename engine=innodb;

那么我们来说说我们为什么要反对这个事情,

1 这么多数据库,这么多表,并且这些表其中有大表,操作这个部分的时间不可控,业务是不会等你操作完 optimize table 然后在去工作,他要anytime anywhere的运行,如果进行了optimize table DB 无法控制表不可用的时间,因为有些表里面N个索引,实际上这就是重建了一张表。然后改名的原子性操作。

2  操作具有风险性,如果此时由于大量运行optimize table 导致IOPS 上升,或者等待这些表的事务持续的等待,undo log 里面的数据无法及时进行purge,最终是否有可能导致数据库出现,基于探针判定主库不可用的问题,导致的数据库切换,这个问题的责任谁来负责。

3  一组数据库有从库,你的语句在此时会直接binlog 给从库,从库也会进行此操作,主库不可用,从库也不可用,并且统统的 UP ,到时我连切换的库都没有。(当然可以在执行时禁止BINLOG 传输此命令,避免从库一起来做相关的操作)

为什么要写此篇文章,因对一些开发人员和架构师的不负责任和缺乏职业素养的问题,非常憎恶。自己一句话,将别人至于尴尬和危险的境地,你于心何忍,你一句话别人要付出什么,这次我怼你算是轻的,下次我可以更狠,你以为做一个 DB 是光看看几篇文章就可以胜任的,笑话。

附群友的一些对此事的看法

4406ceb9b8432934bf52c000d01c2d35.png

另DB 人员自己也的打铁自身重,如果你技不压人,你就只能被人家压!

最后,下面是关于这块的代码,alter table table name  engine= innodb; 

/// Set for ALTER [COLUMN] ... SET DEFAULT ... | DROP DEFAULT
    ALTER_CHANGE_COLUMN_DEFAULT = 1ULL << 8,

    /// Set for DISABLE KEYS | ENABLE KEYS
    ALTER_KEYS_ONOFF = 1ULL << 9,

    /// Set for FORCE
    /// Set for ENGINE(same engine)
    /// Set by mysql_recreate_table()
    ALTER_RECREATE = 1ULL << 10,

    /// Set for ADD PARTITION
    ALTER_ADD_PARTITION = 1ULL << 11,
Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root);

  bool add_field(THD *thd, const LEX_STRING *field_name,
                 enum enum_field_types type, const char *length,
                 const char *decimal, uint type_modifier, Item *default_value,
                 Item *on_update_value, LEX_CSTRING *comment,
                 const char *change, List<String> *interval_list,
                 const CHARSET_INFO *cs, bool has_explicit_collation,
                 uint uint_geom_type, Value_generator *gcol_info,
                 Value_generator *default_val_expr, const char *opt_after,
                 std::optional<gis::srid_t> srid,
                 Sql_check_constraint_spec_list *check_cons_list,
                 dd::Column::enum_hidden_type hidden, bool is_array = false);

 private:
  Alter_info &operator=(const Alter_info &rhs);  // not implemented
  Alter_info(const Alter_info &rhs);             // not implemented
};

/** Runtime context for ALTER TABLE. */
class Alter_table_ctx {
 public:
  Alter_table_ctx();

  Alter_table_ctx(THD *thd, Table_ref *table_list, uint tables_opened_arg,
                  const char *new_db_arg, const char *new_name_arg);

  ~Alter_table_ctx();

  /**
     @return true if the table is moved to another database, false otherwise.
  */
  bool is_database_changed() const { return (new_db != db); }

  /**
     @return true if the table name is changed, false otherwise.
  */
  bool is_table_name_changed() const { return (new_name != table_name); }

  /**
     @return true if the table is renamed (i.e. its name or database changed),
             false otherwise.
  */
  bool is_table_renamed() const {
    return is_database_changed() || is_table_name_changed();
  }

  /**
     @return path to the original table.
  */
  const char *get_path() const {
    assert(!tmp_table);
    return path;
  }

a5985a90dff10c09db1b532768bbc09d.png

<think>我们之前讨论了MySQL优化的一般技术,现在用户具体询问如何优化表性能和存储结构。需要结合之前的引用[1]和MySQL最佳实践来回答。引用[1]提到了查询缓存(尽管在MySQL8.0中已被移除),但用户现在的问题是关于表性能和存储优化,因此我们应侧重于表结构设计、索引优化、存储引擎选择、数据类型选择、分区等。用户问题:“我想优化MySQL表的性能或结构请问如何在MySQL中优化表性能和存储”回答结构:1.分析表结构(包括数据类型、范式等)2.索引优化3.存储引擎选择和配置4.表分区5.碎片整理6.其他优化技术(如垂直/水平拆分)注意:引用[1]中提到了查询缓存,但这表结构优化关系不大,所以我们会侧重其他方面。同时,根据用户上一次的提问,我们之前已经讨论过一些优化技术(如索引、分区),这里可以更深入。要求:生成相关问题,使用中文,LaTeX公式按规则使用(但本问题可能涉及公式较少,如果有表达式则按规则处理)。</think> ### MySQL 表性能存储优化指南 #### 1. 表结构优化 合理设计表结构是性能优化的基础: - **数据类型优化**:选择最小可用数据类型(如用 `TINYINT` 代替 `INT`,`CHAR(10)` 代替 `VARCHAR(255)`) - **规范化设计**:消除冗余数据,遵循第三范式(3NF)[^1] - **垂直拆分**:将大表按访问频率拆分成多个小表 ```sql -- 原始表 CREATE TABLE user_data ( id INT PRIMARY KEY, username VARCHAR(50), last_login DATETIME, profile_text TEXT ); -- 垂直拆分后 CREATE TABLE user_basic (id INT PRIMARY KEY, username VARCHAR(50)); CREATE TABLE user_activity (user_id INT, last_login DATETIME); CREATE TABLE user_profile (user_id INT, profile_text TEXT); ``` #### 2. 索引优化策略 合理索引可显著提升查询性能: ```sql -- 创建复合索引(最左前缀原则) CREATE INDEX idx_name_age ON users(last_name, age); -- 覆盖索引避免回表 SELECT id, name FROM users WHERE status = 'active'; -- 只需创建(status, name)复合索引 -- 定期分析索引效率 ANALYZE TABLE users; SHOW INDEX FROM users; ``` #### 3. 存储引擎选择 | 引擎特性 | InnoDB | MyISAM | |---------|--------|--------| | 事务支持 | ✅ ACID | ❌ | | 行级锁 | ✅ | ❌(表级锁) | | 外键支持 | ✅ | ❌ | | 崩溃恢复 | ✅ | ❌ | | 全文索引 | ✅(5.6+) | ✅ | | 适用场景 | OLTP/高并发 | 只读/报表分析 | #### 4. 碎片整理优化 定期优化表存储减少空间碎片: ```sql -- InnoDB碎片整理(在线操作) ALTER TABLE orders ENGINE=InnoDB; -- MyISAM碎片整理(会锁表) OPTIMIZE TABLE logs; ``` #### 5. 分区表优化 对超大型表使用分区提升查询效率: ```sql -- 按范围分区 CREATE TABLE sensor_data ( id INT AUTO_INCREMENT, sensor_id INT, reading DECIMAL(10,2), log_time DATETIME, PRIMARY KEY (id, log_time) ) PARTITION BY RANGE COLUMNS(log_time) ( PARTITION p2023 VALUES LESS THAN ('2024-01-01'), PARTITION p2024 VALUES LESS THAN ('2025-01-01'), PARTITION pfuture VALUES LESS THAN MAXVALUE ); ``` #### 6. 数据压缩技术 ```sql -- InnoDB页压缩(透明压缩) CREATE TABLE archived_data ( id INT PRIMARY KEY, content BLOB ) COMPRESSION="zlib"; -- 表空间压缩 ALTER TABLE historical_records ROW_FORMAT=COMPRESSED; ``` #### 7. 归档策略 建立数据归档机制提升热点数据性能: ```sql -- 分区表交换归档 ALTER TABLE orders EXCHANGE PARTITION p_archive WITH TABLE orders_archive; ``` #### 8. 统计信息管理 ```sql -- 启用持久化统计(避免查询时动态计算) SET GLOBAL innodb_stats_persistent = ON; -- 设置统计采样页数 ALTER TABLE products STATS_SAMPLE_PAGES = 100; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值