首页 > 数据库 > > 8.4 mysql 优化数据库结构
8.4 优化数据库结构
在作为数据库设计者的角色中,寻找组织方案,表和列的最有效的方法。 与调整应用程序代码时一样,您可以最大限度地减少I / O,将相关项目保留在一起,并提前进行计划,以便随着数据量的增加性能保持较高水平 从有效的数据库设计开始,团队成员可以更轻松地编写高性能的应用程序代码,并使数据库在应用程序演变和重写时可能会持续下去。
8.4.1 优化数据大小
设计您的表以尽量减少磁盘上的空间。 这可以通过减少写入磁盘和从磁盘读取的数据量来实现巨大的改进。 在查询执行期间,较小的表通常需要较少的内存。 表数据的任何空间减少也会导致可以更快处理的更小的索引。
MySQL支持许多不同的存储引擎(表类型)和行格式。 对于每个表格,您可以决定使用哪种存储和索引方法。 为您的应用程序选择适当的表格格式可以为您带来巨大的性能提升。
--第15章 存储引擎
您可以通过使用下面列出的技术来获得更好的表性能和最小的存储空间:
表字段
--也就是说,尽量在保证此列不可能为null的情况下,设置字段的not null 属性
行格式
要请求除DYNAMIC行格式以外的行格式,可以配置innodb_default_row_format或在CREATE TABLE或ALTER TABLE语句中显式指定ROW_FORMAT选项。
compact的行格式使行存储空间减少了大约20%,代价是增加了某些操作的CPU使用量。 如果您的工作负载是受缓存命中率和磁盘速度限制的典型负载,则可能会更快。 如果是受到CPU速度的限制的情况,可能会变慢。
--这种行格式 消耗CPU 来换取对I/O和内存的性能提升。
compact 的InnoDB格式也改变了如何存储包含utf8或utf8mb4数据的CHAR列。 使用ROW_FORMAT=REDUNDANT时,utf8或utf8mb4 CHAR(N)列占用最大字符字节长度×N个字节。 许多语言可以主要使用单字节的utf8或utf8mb4字符编写,所以固定的存储长度通常会浪费空间。
如果需要的话,InnoDB通过去除尾部空格来为这些列分配可变数量的存储空间。 最小存储长度保持为N字节,以便在典型情况下进行就地更新。
索引
joins
Normalization
---配置表,然后需要显示的时候和小配置表连接。
8.4.2 优化器
8.4.2.1 优化数值数据
8.4.2.2 为字符和字符串类型进行优化
对于字符和字符串列,请遵循以下准则:
8.4.2.3 为BLOB 类型优化
8.4.2.4 使用PROCEDURE ANALYSE
ANALYSE([max_elements[,max_memory]])
ANALYZE()检查查询的结果,并返回结果分析,为每列提供最佳数据类型,以帮助减小表的大小。 要获得此分析,请将PROCEDURE ANALYZE附加到SELECT语句的末尾:
SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max_elements,[max_memory]])
例如:
SELECT col1, col2 FROM table1 PROCEDURE ANALYSE(10, 2000);
结果显示了查询返回值的一些统计信息,并为列提出了最佳的数据类型。 这对于检查现有表格或导入新数据之后可能会有所帮助。 您可能需要为参数尝试不同的设置,以便PROCEDURE ANALYZE()在不适用时不建议使用ENUM数据类型。
参数是可选的,用法如下:
8.4.3 优化多个表
一些快速保存单个查询的技术涉及将数据分割到多个表中。 当表的数量达到数千甚至数百万时,处理所有这些表的开销成为新的性能考虑因素。
8.4.3.1 MySQL 如何打开和关闭表
当你执行一个mysqladmin status命令时,你应该看到如下所示:
Uptime: 426 Running threads: 1 Questions: 11082
Reloads: 1 Open tables: 12
如果您只有六个表格,Open表的数值可能会有点令人费解。
MySQL是多线程的,因此可能有很多客户端同时为给定的表发出查询。 为了最小化同一个表上具有不同状态的多个客户端会话的问题,每个并发会话都独立地打开该表。 这使用额外的内存,但通常会提高性能。 使用MyISAM表格,打开表的每个客户端的数据文件都需要一个额外的文件描述符。 (相比之下,索引文件描述符是在所有会话之间共享的。)
table_open_cache和max_connections系统变量影响服务器保持打开的最大文件数量。 如果您增加这些值中的一个或两个,值会根据您的操作系统会收到限制。 许多操作系统允许您增加打开文件的限制,尽管这个方法在不同系统之间差别很大。 请参阅您的操作系统文档,以确定是否有可能增加限制以及如何这样做。
table_open_cache与max_connections有关。 例如,对于200个并发运行连接,请指定至少200 * N的表缓存大小,其中N是您执行的任何查询中每个连接的最大表数量。 您还必须为临时表和文件保留一些额外的文件描述符。
确保您的操作系统可以处理由table_open_cache设置隐含的打开文件描述符的数量。 如果table_open_cache设置得太高,MySQL可能会耗尽文件描述符并拒绝连接,无法执行查询,并且非常不可靠。
您还应该考虑到MyISAM存储引擎为每个独特的打开表格需要两个文件描述符的事实。 对于分区的MyISAM表,打开的表的每个分区都需要两个文件描述符。 (进一步注意,当MyISAM打开一个分区表时,它会打开这个表的每个分区,无论是否实际使用了一个给定的分区,请参见MyISAM和分区文件描述符的用法)。可以为mysqld 增加MySQL可用的文件描述符的数量 --open-files-limit的启动选项改。
打开的表的缓存保持在table_open_cache条目的级别。 服务器在启动时自动调整缓存大小。 要显式设置大小,请在启动时设置table_open_cache系统变量。 请注意,MySQL可能会暂时打开更多的表来执行查询。
在下列情况下,MySQL关闭一个未使用的表并将其从表缓存中删除:
当表缓存填满时,服务器使用以下过程来查找要使用的缓存条目:
MyISAM表为每个并发访问打开。 这意味着,如果两个线程访问同一个表,或者一个线程在同一个查询中访问了两次表(例如,通过将表连接到自己),则需要打开两次表。 每个并发打开需要在表缓存中的条目。 任何MyISAM表的第一次打开需要两个文件描述符:一个用于数据文件,一个用于索引文件。 每个额外使用这张表仅为数据文件使用一个文件描述符。 索引文件描述符在所有线程之间共享。
--也就是说,2个线程访问一张表,或者2个表连接到自己,需要打开3个描述符,2个数据文件,1个索引文件。
如果使用HANDLER tbl_name OPEN语句打开表,则为该线程分配一个专用表对象。 此表对象不被其他线程共享,并且在线程调用HANDLER tbl_name CLOSE或线程终止之前不会关闭。 发生这种情况时,该表将放回表缓存中(如果缓存未满)。
您可以通过检查mysql状态变量Opened_tables来确定您的表缓存是否太小,该变量指示自服务器启动以来的表开放操作数:
mysql> SHOW GLOBAL STATUS LIKE 'Opened_tables';
| Variable_name | Value |
| Opened_tables | 2741 |
如果值非常大或快速增加,则即使未发出多个FLUSH TABLES语句,也要增加表缓存大小。
8.4.3.2 在同一数据库中创建多个表的缺点
如果在同一个数据库目录中有许多MyISAM表,打开,关闭和创建操作很慢。 如果在许多不同的表上执行SELECT语句,那么当表缓存满时,会有一些额外的开销,因为对于每个必须打开的表,必须关闭另一个表。 您可以通过增加表缓存中允许的条目数来减少此开销。
---表太多了会占用大量的缓存,并且当占满之后,每次新开表,都要去释放旧表。
8.4.4 MySQL如何使用内部临时表
在某些情况下,服务器在处理查询时创建内部临时表。 用户无法直接控制服务器何时执行此操作。 一个内部临时表可以放在内存中,由MEMORY存储引擎处理,或者存储在磁盘上。 服务器最初可能会创建一个内部临时表作为内存表,如果它变得太大,则将其转换为磁盘上的表。 从MySQL 5.7.5开始,internal_tmp_disk_storage_engine系统变量确定服务器使用哪个存储引擎来管理磁盘上的内部临时表。 值可以是MYISAM或INNODB。 MySQL 5.7.5中的默认值是MYISAM。 在MySQL 5.7.6中,默认是INNODB。 在MySQL 5.7.5之前,服务器总是使用MyISAM。
临时表可以在如下条件下创建:
要确定语句是否需要临时表,请使用EXPLAIN并检查Extra列以查看是否使用了临时表。 EXPLAIN不一定会为派生或物化临时表说Using temporary。
如果内部临时表最初是作为内存表创建的,但是变得太大,MySQL会自动将其转换为磁盘上的表。内存中临时表的最大大小是tmp_table_size和max_heap_table_size值中的最小值。 这与使用CREATE TABLE显式创建的MEMORY表不同:对于这样的表,只有max_heap_table_size系统变量决定允许表被增长到多少,并且不会转换为磁盘格式。
从MySQL 5.7.5开始,可以通过设置internal_tmp_disk_storage_engine系统变量来指定服务器用于磁盘内部临时表的存储引擎。 允许的值是MYISAM(默认值)和INNODB。
当服务器创建一个内部临时表(无论是在内存中还是在磁盘上),它都会增加Created_tmp_tables状态变量。 如果服务器在磁盘上创建表(initially或通过转换内存表),它将增加Created_tmp_disk_tables状态变量。
注意:
当使用internal_tmp_disk_storage_engine = INNODB时,生成超过InnoDB行或列限制的磁盘内部临时表的查询将返回行大小过大或列错误过多。 解决方法是将internal_tmp_disk_storage_engine设置为MYISAM。
某些查询条件会阻止使用内存中的临时表,在这种情况下,服务器会使用磁盘上的表:
从MySQL 5.7.3开始,服务器不会为满足特定条件的UNION语句使用临时表。 替代的是,它保留临时表创建执行结果列类型转换所需的数据结构。 该表没有完全实例化,没有行被写入或读取; 行直接发送到客户端。 结果是减少了内存和磁盘需求,并且在第一行发送到客户端之前有较小的延迟,因为服务器不需要等到最后的查询块被执行。 EXPLAIN和优化器跟踪输出反映了这种执行策略:UNION RESULT查询块不存在,因为该块对应于从临时表读取的部分。
不具备临时表的union评估条件是:
内部临时表存储引擎
一个内部临时表可以保存在内存中并由MEMORY存储引擎处理,或由InnoDB或MyISAM存储引擎存储在磁盘上。
内存中的临时表由MEMORY存储引擎管理,该引擎使用固定长度的行格式。 将VARCHAR和VARBINARY列值填充到最大列长度,实际上将它们存储为CHAR和BINARY列。
磁盘上的临时表由InnoDB或MyISAM存储引擎管理(取决于internal_tmp_disk_storage_engine设置)。 两个引擎都使用动态宽度的行格式存储临时表。 列只占用尽可能多的存储空间,与使用固定长度行的磁盘表相比,它减少了磁盘I / O和空间要求,并减少了处理时间。
对于最初在内存中创建内部临时表的语句,然后将其转换为磁盘表,通过跳过转换步骤并在磁盘上创建表来开始,可以获得更好的性能。 big_tables系统变量可用于强制内部临时表的磁盘存储。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69946831/viewspace-3125488/ ,如需转载,请注明出处,否则将追究法律责任。