我阅读了与优化表相关的文章,需要进一步澄清。
我对MariaDBv10.6.7运行了一个mysqltuner.pl,得到了一些建议,其中一个建议是运行优化表。
Run OPTIMIZE TABLE to defragment tables for better performance
OPTIMIZE TABLE `DB`.`TableA`; -- can free 426 MB
Total freed space after theses OPTIMIZE TABLE : 426 Mb
问题:
1.是否可以在InnoDB表中运行OPTIMIZE TABLE 'TableA'以获得更好的性能(据我所知,它会清除磁盘中未使用的空间,但它会有助于提高性能)?
1.因为我使用的是InnoDB,所以它说“表不支持优化,而是进行重新创建+分析”。我需要运行Alter Table ... OPTIMIZE而不是OPTIMIZE TABLE吗(我猜两者都是链接的)?
1.即使我按照建议运行了优化表,我仍然看到表426MB没有被它完全释放(它被减少到384MB)。我们不能释放整个大小吗?
> select * from information_schema.TABLES where TABLE_NAME = "TableA"\G;
***************************1. row***************************
TABLE_CATALOG: def
TABLE_SCHEMA: DB
TABLE_NAME: TableA
TABLE_TYPE: BASE TABLE
ENGINE: InnoDB
VERSION: 10
ROW_FORMAT: Dynamic
TABLE_ROWS: 1600474
AVG_ROW_LENGTH: 207
DATA_LENGTH: 332136448
MAX_DATA_LENGTH: 0
INDEX_LENGTH: 0
DATA_FREE: 446693376 (426MB)
AUTO_INCREMENT: NULL
CREATE_TIME: 2022-08-09 16:01:05
UPDATE_TIME: 2022-08-09 16:04:47
CHECK_TIME: NULL
TABLE_COLLATION: utf8_general_ci
CHECKSUM: NULL
CREATE_OPTIONS: partitioned
TABLE_COMMENT:
1 row in set (0.01 sec)
ERROR: No query specified
> optimize table TableA;
+-----------+----------+----------+--------------------------------------------------------------------+
| Table | Op | Msg_type | Msg_text |
+-----------+----------+----------+--------------------------------------------------------------------+
| DB.TableA | optimize | note | Table does not support optimize, doing recreate + analyze instead |
| DB.TableA | optimize | status | OK |
+-----------+----------+----------+--------------------------------------------------------------------+
2 rows in set (8.25 sec)
127.0.0.1:3307> select * from information_schema.TABLES where TABLE_NAME = "TableA"\G;
***************************1. row***************************
TABLE_CATALOG: def
TABLE_SCHEMA: DB
TABLE_NAME: TableA
TABLE_TYPE: BASE TABLE
ENGINE: InnoDB
VERSION: 10
ROW_FORMAT: Dynamic
TABLE_ROWS: 1600474
AVG_ROW_LENGTH: 193
DATA_LENGTH: 310116352
MAX_DATA_LENGTH: 0
INDEX_LENGTH: 0
DATA_FREE: 402653184 (384MB)
AUTO_INCREMENT: NULL
CREATE_TIME: 2022-08-09 16:47:00
UPDATE_TIME: NULL
CHECK_TIME: NULL
TABLE_COLLATION: utf8_general_ci
CHECKSUM: NULL
CREATE_OPTIONS: partitioned
TABLE_COMMENT:
1 row in set (0.27 sec)
使用与www.example.com中相同的逻辑mysqltuner.pl来查找可用大小。不确定查询背后的逻辑。
SELECT CONCAT(CONCAT(TABLE_SCHEMA, '.'), TABLE_NAME),cast(DATA_FREE as signed) FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('information_schema','performance_schema', 'mysql') AND DATA_LENGTH/1024/1024>100 AND cast(DATA_FREE as signed)*100/(DATA_LENGTH+INDEX_LENGTH+cast(DATA_FREE as signed)) > 10 AND NOT ENGINE='MEMORY' $not_innodb
更新1:
根据要求,添加了tableA的输出
> SHOW TABLE STATUS WHERE name LIKE "TableA"\G;
***************************1. row***************************
Name: TableA
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 1875385
Avg_row_length: 3
Data_length: 5685248
Max_data_length: 0
Index_length: 0
Data_free: 1991245824
Auto_increment: NULL
Create_time: 2022-10-25 10:53:40
Update_time: 2022-10-25 11:34:32
Check_time: NULL
Collation: utf8mb3_general_ci
Checksum: NULL
Create_options: partitioned
Comment:
Max_index_length: 0
Temporary: N
1 row in set (0.002 sec)
> Show create table TableA;
| TableA | CREATE TABLE `TableA` (
`Col1` mediumint(8) unsigned NOT NULL,
`Col2` tinyint(4) NOT NULL,
`Col3` tinyint(4) NOT NULL,
`Col4` tinyint(4) NOT NULL,
`Col5` tinyint(4) NOT NULL,
`Col6` smallint(4) NOT NULL,
`timestamp` int(11) NOT NULL,
`Col7` bigint(20) DEFAULT NULL,
`Col8` bigint(20) DEFAULT NULL,
`Col9` tinyint(4) DEFAULT NULL,
:::
`Col40` tinyint(4) DEFAULT NULL,
PRIMARY KEY (`Col1` ,`Col2` ,`Col3` ,`Col4` ,`Col5` ,`Col6`,`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3
PARTITION BY RANGE (`timestamp`)
(PARTITION `p2022_10_11_02_00_00` VALUES LESS THAN (1665437400) ENGINE = InnoDB,
PARTITION `p2022_10_11_03_00_00` VALUES LESS THAN (1665441000) ENGINE = InnoDB,
PARTITION `p2022_10_11_04_00_00` VALUES LESS THAN (1665444600) ENGINE = InnoDB,
....
PARTITION `p2022_10_25_12_00_00` VALUES LESS THAN (1666683000) ENGINE = InnoDB)
//partitioned by timestamp. Partitioned more than 360
3条答案
按热度按时间t3psigkw1#
简短回答:“永远不要”在InnoDB表上使用
OPTIMIZE TABLE
。(这基本上是浪费时间。即使您看到了改进,它也会很快被吞噬掉。)为什么在你的情况下没有节省呢?每个
PARTITION
预先分配4 MB-7 MB的“自由”空间。“建议”没有注意到这一点;所以你没有存款。如果你需要对很多行进行
DELETE
,我们来谈谈。通常有更好的方法来完成这一任务,而且它们不会导致你去做OPTIMIZE
。这个表有大约70个分区?而只有160万行?你从
PARTITIONing
中得到了什么好处吗?(我怀疑)给我们看看主要的查询;我将带您进入一些更好的索引和没有分区。u1ehiz5o2#
从你的问题中的信息来看,你的数据库一切都很好。
1.是的,在生产表上使用OPTIMIZE是可以的。它和它的InnoDB时代的替代品使用联机数据定义语言语句。
1.当您对InnoDB表使用OPTIMIZE TABLE时,服务器会执行正确的操作。
1.像www.example.com这样的调优工具sqltuner.pl提供了有关节省空间等方面的 * 估计 ,而不是硬性数字。
1.在许多情况下,很难衡量OPTIMIZE TABLE所带来的性能改进。具有FULLTEXT索引的忙碌表是个例外。
有些背景。
当应用程序更改表(使用INSERT、UPDATE和DELETE)时,有时会在表的数据结构中留下未使用的空间。UPDATE行以将较长得VARCHAR()值更改为较短得值.
FULLTEXT索引在变更时也会留下空白空间。
诊断程序.和information_schema.TABLES.DATA_FREE, 估计 * 在您重组(优化)表后可用的空间。这些估计值对于传统的MyISAM存储引擎比对于像InnoDB这样的新存储引擎更准确。因此,您的表重组没有产生您的工具估计的那么多可用空间并不奇怪。
一些参考资料:
ctrmrzij3#
使用OPTIMIZE TABLE对InnoDB表进行碎片整理,这可能会减小大小,尤其是在发生大数据更改(如批量删除)之后。
但实际上,它并不能显著提高性能。性能不是使用OPTIMIZE TABLE的原因。
关于“Table does not support optimize”的错误消息是因为它并不像OPTIMIZE TABLE那样在旧的MyISAM存储引擎上执行相同的操作。对于InnoDB,它确实支持该语句,并且它确实做了一些有用的事情:将行复制到一个新的表空间,并在此过程中重建二级索引。
对于InnoDB,
OPTIMIZE TABLE <name>
的作用与ALTER TABLE <name> FORCE
或ALTER TABLE <name> ENGINE=InnoDB
相同。ALTER TABLE <name> OPTIMIZE
没有语法(除了指定的分区)。至于你的神秘的高“data_free”,我想知道你是不是把这个表存储在shared system tablespace中,也就是说,配置选项
innodb_file_per_table
被禁用了,这导致表一起存储在系统表空间中,按照惯例,系统表空间是在数据目录下的一个文件ibdata1
中。如果表位于系统表空间中,则OPTIMIZE TABLE不会将表复制到新的表空间中,它只是将数据移动到系统表空间的不同区域中,并且不会恢复任何空闲空间。此外,报告整个表空间的“data_free”,而不仅仅是各个表的“data_free”。在优化该表空间中的表后,“data_free”可能不会有太大变化。
您可以通过以下方式检查表占用了哪些表空间:
系统表空间的空间ID为0。如果不是0,则表位于自己单独的表空间中。
我希望人们不要使用mysqltuner。
众所周知,mysqltuner提供的建议不可靠。我见过一些案例,它的建议表明作者对MySQL的内部结构了解不够,无法提供建议。我认为mysqltuner是导致大量不必要工作的原因。
下面是一些过去的例子,我试图纠正那些被mysqltuner报告弄糊涂的人的误解: