MySQL数据目录详解(SQL语句与表文件的对应关系、操作系统对数据库对象名字的约束、影响表最大长度的因素、数据目录结构对系统性能的影响、MySQL状态文件和日志文件)

一、SQL语句与表文件的对应关系

  • 每一种存储引擎都使用了一个.frm文件来存储表格式(定义),因此SHOW TABLE FROM db_name语句的输出结果与db_name的数据库目录里的那个.frm文件的基本名列表相同。

CREAATE TABLE

  • 在创建MySQL所支持的任意类型的表时,需要执行CREATE TABLE语句来定义表的结构,并且其中还要包括ENGINE=engine_name子句,用于表明想要使用哪种存储引擎。如果省略ENGINE子句,那么MySQL将使用默认存储引擎(如果你未更改,则为InnoDB存储引擎)。
  • 服务器会为新表创建一个.frm文件,在其中存储该表定义的内部编码,并且会告知相应的存储引擎去创建与该表相关联的其他文件。例如:
    • InnoDB会创建一个数据字典条目,并在相应的InnoDB表空间里对其数据和索引信息进行初始化。
    • MylSAM会创建一个.MYD数据文件和一个.MYI索引文件;
    • 而CSV存储引擎会创建一个.CSV数据文件。
  • 在Unix系统里,为表示这个表而创建的所有文件的所有者和访问模式,都被设置成了只允许用来运行MySQL服务器的那个登录账户进行访问

ALTER TABLE

  • 当执行ALTER TABLE语句时,服务器会对表的.frm文件重新编码,以反映出这条语句对其结构的更改;同时,服务器还会修改表的内容(即数据和索引)。在执行语句CREATE INDEX和DROP INDEX时,也会发生这种情况,因为服务器会把它们当作ALTER TABLE的等效语句来处理。
  • 如果ALTER TABLE语句更改了表的存储引擎,那么表的内容也会被转换到新的存储引擎,新引擎会使用用于表示表的那些文件的恰当类型重新写入那些内容。

DROP TABLE

  • MySQL实现DROP TABLE语句的方式是,删除那些表示表的文件
  • 如果是删除InnoDB表,那么InnoDB存储引擎还会更新它的数据字典,并在InnoDB系统表空间里把与该表相关联的空间标记为空闲。
  • 对于某些存储引擎,如MylSAM,可以通过在表相对应的那个数据库目录里删除文件的方式手动删除该表。
  • 对于其他的存储引擎,如InnoDB或MEMORY,由于表的部分内容可能不是以文件系统里的文件来表示的,因此没有与DROP TABLE语句等效的文件系统命令。例如,存储在系统表空间里的InnoDB表,总是有一个.frm文件与之对应,但是删除这个文件并不能彻底删除该表。InnoDB数据字典只能由InnoDB自己更新,并且如果只删除.frm文件,则会导致表的数据和索引“搁置”在系统表空间里。
  • 如果InnoDB表有其自己的独立表空间,那么它会在数据库目录里表示成.frm文件和其自己的.ibd文件。但是,通过删除这些文件的方式来删除表,仍然是不正确的,因为InnoDB存储引擎还是没有机会更新数据字典。因此,必须使用DROPT ABLE语句,这样InnoDB存储引擎才能在删除文件的同时更新其数据字典。

二、操作系统对数据库对象名字的约束

  • 在命名数据库和其他对象(如表)的标识符时,MySQL有一套自己的标识符命名规则。https://dongshao.blog.csdn.net/article/details/87353783中详细列出了这些规则,这里再简要概括一下。
    • 不加引号的标识符可以由大小写形式的字母a-z、数字0-9、美元符号"$"、下划线"_"以及范围在U+0080到U+FFFF之间的Unicode扩展字符构成。
    • 反引号引起来的标识符可以包含其他字符(如`odd?name!`)。
      • 如果使用SQL保留字作为标识符,则也需要使用反引号将其引起来
      • 如果启用了SQL的ANSI_QUOTES模式,那么这些标识符既可以用反引号,也可以用双引号。
    • 标识符的最大长度为64个字符
  • 此外,MySQL服务器所在主机的操作系统也可能对标识符施加其他限制。这些限制源于文件系统的命名规则,因为数据库名和表名都对应着目录名和文件名:在文件系统里,每个数据库都是以数据库目录的形式进行表示的,并且不管使用何种存储引擎,每个表在文件系统里都至少会与一个.fm文件相对应。因此,在命名MySQL标识符的时候还要考虑以下限制:
    • MySQL允许的数据库名和表名的最大长度为64个字符,但这些名字的长度都不得超过操作系统所允许的最大长度。
    • 底层文件系统是否区分大小写,会对数据库和表的命名与引用产生影响。如果文件系统分大小写(对于Unix系统通常是这样),那么文件名abc和ABC所指的就是两个不同的文件。如果文件系统不区分大小写(如Windows系统或者MacOSX系统的扩展文件系统),那么文件名abc和ABC所指的就是同一个文件。如果在某个文件名区分大小写的服务器上开发了一个数据库,并且可能需要把这个数据库移动或复制到另一个文件名不区分大小写的服务器上,则需要对此问题引起注意。

特殊编码

  • MySQL服务器会对标识符里可能导致文件名出现问题的特殊字符进行编码
  • 这个编码允许在SQL语句里出现的那些名字当中,使用像"/"和"\"这样的字符:在数字和拉丁字母以外的所有字符在文件名里都将被应映射成,“@”后面紧跟一个编码后的字符值。
  • 例如,字符“?”和“!”的编码值为003f和00021,那么odd?name!表所对应的.frm文件的名字即为odd@003fname@0021.frm。与表相关联的其他文件的命名方式与此类似。
  • 之前提到过,文件系统区分大小写会对数据库和表的命名产生影响。解决此问题:
    • 一种是固定使用一种大小写形式的名字
    • 另一种办法是在启动服务器时,将lower_case_table_names系统变量设置为1,这个设置有下面两个效果。
      • 在为某个表创建相应的磁盘文件之前,服务器会先把该表的名字转换为小写。
      • 在语句里引用这个表时,服务器会在试图到磁盘上查找这个表之前,把它的名字转换为小写。
  • 这两种做法的结果是,不管文件系统是否区分大小写,所有名字都不会区分大小写。如此一来,在系统间移动数据库和表会变得更容易。
  • 不过,这里提醒一下,如果打算使用这种策略,则必须在开始创建数据库或表之前(而不是之后)通过服务器配置,将lower_case_table_names系统变量设置为1。如果在设置此变量之前,已经创建了数据库或表,而且其名字里包含有大写字母,那么这个设置将无法产生预期的效果,因为磁盘里已经存储了某些不全为小写字母的名字。为避免出现这个问题,可以先把名字里有大写字母的表全部重新命名为小写字母形式,然后再来设置lcwer_case_table_names系统变量。(可以用ALTER TABLE或RENAME TABLE语句来重新命名表)。如果你有很多表需要重新命名,或者有许多数据库的名字包含大写字母,那么更简单的办法是先转储这些数据库,然后在设置了lower_case_table_names系统变量之后,再重新创建它们。
    • (1)用mysqldump工具将各个数据库转储出来:mysqldump --database db_name > db_name.sql
    • (2)用DROPDATABASE语句删除这些数据库。
    • (3)关闭服务器,重新配置它,将lower_case_table_names设置为1,然后重启服务器。
    • (4)用mysql程序重新加载所有的转储文件:mysql < db_name.sql
  • 由于设置了lower_case_table_names,所有的数据库和表在重新创建之后在磁盘里的名字将全部为小写。
  • lower_case_table_names实际上还有另外几个可取值,详细信息请参阅相关文档。

三、影响表最大长度的因素

  • 在MySQL里,表的长度是有限的,不过表的长度受很多方面的限制,因此很难精准地确定具体的界限。

操作系统限制

  • 操作系统对文件的最大长度有限制。那些用于表示表的文件,如MylSAM表的.MYD和.MYI文件,也会受这种限制的影响
  • 这种限制也适用于构成InnoDB表空间的那些文件。不过,InnoDB系统表空间的总长度很容易超过文件的最大长度。为解决此问题,可以把表空间配置为由多个文件文件组成,其中每个文件都可以达到最大长度。
  • 另一种突破文件大小限制的方法是在InnoDB表空间里使用磁盘里的原始分区。磁盘原始分区上的表空间组件可以与磁盘分区本身一样大。与配置指导有关的更多信息请参考后面"存储引擎配置"文章。

内部限制

  • 除了操作系统的限制以外,MySQL对于表的长度还有其自己的内部限制。这些限制因存储引擎的不同而有所区别。
  • 例如对于InnoDB存储引擎
    • InnoDB系统表空间的最大长度为40亿页,其中每页的大小为16KB。表空间的最大长度也是存储在表空间里的单个InnoDB表的长度上限
    • 如果把存储引擎InnoDB配置为使用独立表空间,则每个InnoDB表的内容将存储在其自己的.ibd文件里。此时,InnoDB表的长度将受限于操作系统的文件大小上限
  • 例如对于MylSAM表:
    • .MYD和.MYI文件的最大长度默认为256TB。但是,在创建表的时候,如果使用了AVG_ROW_LENGTH和MAX_ROWS选项,这些文件的大小上限将可达到65536TB。
    • 这些选项会对MySQL内部的行指针宽度产生影响,而这个宽度则决定着表所能容纳的最大行数。
    • 当MylSAM表增长到其最大长度,并且出现了与表操作有关的135或136号错误时,可以使用ALTER TABLE语句来增大这些选项值
    • 如果想要直接更改默认的MylSAM指针宽度,可以设置myisam_data_pointer_size系统变量,新设置会对此后创建的表生效。
  • 对于使用不同文件表示数据和索引的存储引擎,只要其中有一个文件达到文件大小上限,那么这个表的长度就会达到上限。对于MylSAM表,其索引情况也会对哪种类型的文件先到达上限造成影响。对于没有索引或者索引比较少的表,很可能是数据文件先到达上限。对于有大量索引的表,则很可能会是索引文件先到达上限。
  • AUTO_INCREMENT列会隐式限制表所能拥有的行数。例如,若列的类型为TINYINT UNSIGNED,其所能容纳的最大值为255,那么表可能具有的最大行数也将是255。更大的整数类型允许有更多的行。更一般的情况是,如果表包含PRIMARY KEY或UNIQUE索引,那么它的行总数将不超过索引中唯一值的数目。
  • 为了确定实际可能达到的最大表长度,必须考虑到所有可能的因素。有效的最大表长度可能由那些因素中的最小值来确定。假设,你想创建一个MylSAM表。当使用默认数据指针大小时,MySQL允许数据和索引文件各自达到256TB。但是,如果操作系统限制文件大小为2GB,那么表文件的有效上值也将为2GB。另外,如果系统支持大于256TB的文件,那么决定表长度的因素将是MySQL,即那个内部数据指针大小。这个因素是你可以控制的。
  • 对于存储在系统表空间里的InnoDB表,单个的InnoDB表可以增大到与表空间一样大,而表空间可以跨多个文件,因而可以变得非常大。但是,很有可能你会拥有许多InnoDB表,它们都共用同一个空间,这样一来,每个表不仅要受限于表空间的长度,还要受限于为其他表分配了多少表空间。只要表空间未被填满,任何InnoDB表都可以不断增大。相反,当表空间被填满时,InnoDB表则不能再增大,除非往这个表空间里增加另外的组件,使之变得更大。另一种做法是,使最后那个表空间组件可以自动扩展,这样,只要这个表空间组件没有超过系统文件的大小上限,并且还有可用的磁盘空间,那么它便能继续增大。与配置指导有关的更多信息请参考后面"存储引擎配置"文章。

四、数据目录结构对系统性能的影响

  • MySQL数据目录的结构比较容易理解,因为它以一种很自然的方式使用了文件系统的分层结构。同时,这种结构也隐含着会有一些性能方面的问题,特别是对于打开文件(用于表示数据库表的)的操作更是如此。
  • 对于那些使用其自己的文件来单独表示各个表的存储引擎,每次打开表都会需要一个文件描述符。如果某个表由多个文件表示,那么打开这个表将需要多个文件描述符,而不是只需要一个。
  • MySQL服务器会智能地缓存这些文件描述符,但是对于一个繁忙的服务器,在同时为大量的客户端连接提供服务,或者执行引用了多个表的复杂语句时,会很容易耗尽这些描述符。这很可能成为一个问题,因为文件描述符在许多系统里都属于稀缺资源。尤其是在那些把每个进程的默认文件描述符最大个数设置得相当低的系统上,更是如此。
  • 如果某个操作系统在这方面设置了一个很低的上限值,并且没有提供增大这个值的手段,那么它就不是运行髙负荷MySQL服务器的最佳选择。
  • 对于每个表都用其自己的文件进行表示这一做法,其另一个影响是,表的打开时间会随着表数量的增加而增大。表的打开操作会映射到操作系统提供的文件打开操作上,从而会受到系统目录查找例程效率的约束。
  • 通常情况下,这不会有多大问题,但是,当数据库里需要有大量表时,这个问题便需要认真考虑。例如,一个MylSAM表由3个文件表示。如果你需要10000个MylSAM表,数据库目录将包含30000文件。在有了这么多文件之后,你便会发现,表的打开操作慢了下来,因为文件打开操作需要花费时间。如果出现了这个问题,你可能会需要考虑使用一种能高效处理大量文件的文件系统。
  • 例如,即使有大量的小文件,XFS或JFS仍可以表现出良好的性能。如果不能选择另一种文件系统,则必须根据应用程序的需要重新评估一下表的结构,并且相应地重新组织表。仔细考虑一下是否真的需要这么多的表,很多时候应用程序根本不需要这么多表。为每个用户创建一个表的应用程序,会产生许多表,而这些表都拥有相同的结构。如果想要把这些表组合为一个表,可能只需在其中增加一列,用于标识每一个行属于哪一个用户即可。如果这样能显著减少表的数量,那么应用程序的性能将会得到提髙。
  • 在设计数据库时,一定要考虑这种决策是否适用于给定的应用程序。不用刚才描述这种方式合并表的原因如下:
    • 需要增加磁盘空间。合并表可以减少所需表的数量(减少表打开时间),但是会多增加一列(增加对磁盘空间的需求)。这是典型的时间与空间的权衡问题,需要你来决定哪一个因素最为重要。如果速度最重要,那么你可能愿意牺牲一点额外的磁盘空间。如果空间比较紧张,那么使用多个表可能也是可以接受的,虽然有些延迟。
    • 出于安全性的考虑。这些因素可能会对你合并表的能力和期望产生束缚。让每个用户单独使用一个表的原因在于,每个表只允许具有表级权限的用户进行访问。如果合并了表,则所有用户的数据都会在同一个表里。MySQL没有提供限制某个给定用户只能访问特定行的功能,因此,在进行表合并时,不能再想着对行进行访问控制。一种可行的办法是使用只能选择当前用户行的视图,并为这些视图授予访问权限。另外,如果所有的数据访问是受应用程序控制的(用户绝不能直接连接到数据库),那么可以合并表,并且使用应用程序逻辑来实施对合并结果的行级访问。
  • 另一种创建大量无需如此多单个文件的表的办法是,使用InnoDB表
    • InnoDB将它们存储在InnoDB系统表空间里。在这种情况下,InnoDB存储引擎只会与每个表仅有的.frm文件相关联,并且会把所有InnoDB表的数据和索引信息都存储在一起。这样可以减少表示这些表所需要的磁盘文件数量,从而也会大量减少打开表所需的文件描述符数量。
    • 对于表空间里的每一个组成文件,InnoDB只需要一个描述符即可(在服务器进程存活期间,这是个恒定的值),简单地讲,对于它所打开的任何表,在它读取这个表的.frm文件时,只需打开一个描述符。

五、MySQL状态文件和日志文件

  • 除了数据库目录之外,MySQL数据目录还含有许多状态文件和日志文件,如下图所示:

  • 这些文件的默认位置为服务器的数据目录,其中许多默认名是从在表中表示为HOSTNAME的服务器主机名称继承来的。二进制日志和中继日志都会被创建为一组带编号(用nnnnn表示)的文件。上面表格只列出了服务器级的状态文件和日志文件。个别存储引擎可能还会创建它们自己的日志或其他文件。例如,InnoDB存储引擎便是如此。
  • 对于常规的查询日志和慢査询日志,可以选择让服务器把日志信息写入日志文件,或者写入mysql数据库里的日志表,或者写到这两个地方。关于日志信息写入表的更多信息在后面文章会介绍。

进程ID文件

  • MySQL服务器会在启动时把它的进程ID(PID,processID)写入PID文件,并且在关闭时会删除该文件。其他进程可以利用这个文件来确定MySQL服务器是否在运行,以及其进程ID是什么(如果在运行的话)。
  • 例如,如果操作系统在关闭时调用mysql.server脚本来停止MySQL服务器,那么该脚本会检査PID文件,确定它应该向哪个进程发出终止运行信号
  • 如果服务器无法创建PID文件,那么它会往出错日志里写入一条信息,然后继续。

MySQL日志

  • MySQL能够维护多种类型的日志文件。大部分日志功能都是可选的,你可以使用服务器启动选项来启用需要的日志,也可指定它们的名字,如果你不喜欢那些默认名字的话。请注意,日志文件有可能会变得非常大,因此千万不要让它们把文件系统的空间都占满。应该定期对日志文件进行过期处理,以保证它们所占用的空间总量总在限定范围之内。
  • 下面只简要地介绍几种常用的日志文件。与日志、控制服务器日志行为的选项以及日志过期处理有关的更多信息在后面文章会详细介绍。
  • 错误日志(error log)包含的是,服务器在系统发生意外状况时生成的诊断信息。如果服务器启动失败,或者意外退出,那么这个日志会非常有用,因为它通常都包含了出现问题的具体原因。
  • 常规査询日志(general query log)包含的是与服务器操作有关的常规信息,其中包括谁在连接服务器、从什么地方连接以及它们都调用了哪些语句。二进制日志还包含语句信息,但是仅限于那些修改数据库内容的语句。当这台服务器在复制结构里属于主服务器时,它还会包含其他的信息,如保持从服务器同步所需要的时间戳。二进制日志的内容是一些以二进制格式记录的“事件”,这些事件可以作为mysql客户端程序的输入来执行。配套的二进制日志索引文件会列出服务器当前正在维护的二进制日志文件。
  • 二进制日志对系统崩溃后的数据库恢复工作有着重要意义,因为在进行备份之后,可以通过把二进制日志文件送至服务器的方式重复这些更新操作。这样你便可以把数据库恢复到发生崩溃前的那一刻。即便你建立了复制服务器,二进制日志也能发挥作用,因为它可以把那些必须从主服务器传递到从服务器的的更新操作记录下来。
  • 一定要确保你的日志文件是安全的,并且不能随意被其他用户读取,因为其中的语句文本里可能包含密码之类的敏感信息。例如,下面这条日志记录便会把root用户的密码显示出来,这个可不是任何人都可以访问的信息:

  • 默认情况下,服务器会把日志文件写到数据目录里,因此,确保日志文件安全的一种措施是,只允许MySQL系统管理员所使用的登录账户访问服务器主机上的数据目录。有关这个步骤的详细设置在后面"爆出对MySQL文件系统的访问"文章会介绍。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董哥的黑板报

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值