电脑技术学习

Mysql入门系列:MySQL数据目录的结构

dn001
;;;;MySQL数据目录中包含由服务器管理的所有数据库和表。它们被组织成一个树状结构,该结构是通过UNIX 或Windows 文件系统的层次结构用简单的方式实现的:
每个数据库对应该数据目录下的一个目录。
数据库中的表对应数据库目录中的文件。
数据目录还包含几个由服务器生成的状态文件,如日志文件。这些文件提供了关于服务器运作的重要信息,对管理员是有用的,尤其是当问题出现且试图确定问题的原因时特别有用。例如,如果某个特定的查询毁坏了数据库,您可以通过检查日志文件来识别这个讨厌的查询。

MySQL服务器怎样提供对数据的访问

数据目录中的一切都由一个单个的实体进行管理,即MySQL服务器的mysqld。客户机程序不能直接操纵数据。而服务器提供了访问数据库的唯一的连结点,它担当着客户机程序和所需数据之间的媒介(参见图10 - 1)

当启动服务器时,如果有任何请求,它都将打开日志文件,然后通过对网络连接的监听向数据目录展现网络接口。为了访问数据,客户机建立一个到服务器的连接,然后传达作为SQL 查询的请求,以完成所期望的操作(例如,创建表、选择记录、更新记录)。服务器执行每个操作并将结果发送回客户机。服务器是多线程的,可以服务于多个并发的客户机的连接。但是,由于更新操作一次只能执行一个,因此实际上这些请求是顺序化的,两个客户机决不可能在同一时刻修改同一个记录。
在正常条件下,使服务器担当数据库访问的唯一仲裁者将提供对防止各种讹误的担保,这些讹误可导致多个进程同时访问数据库的表。然而,管理员应该知道:存在着服务器不具有对数据目录独占控制的时期:
何时在单个数据目录中运行多个服务器。通常情况下是运行一个单个的服务器来管理主机中的所有数据库,但是运行多个服务器也是可能的。如果这样做可以提供对多个独立的数据目录的访问,则不存在交互作用的问题。但是,有可能启动多个服务器并在相同的数据目录中指向它们。这是一个好主意,如果您想试试它,最好应确保系统提供了良好的文件锁定性能,否则服务器之间将不能协调地工作。如果将多个服务器同时写入日志文件,则将会使日志文件成为混乱的来源(而不是有用信息的来源)。
何时运行isamchk 和my i s a m c h k。isamchk 和myisamchk 实用程序用于表的维护、故障排除和修复。正如您所猜测的,由于这些实用程序能改变表的内容,所以如果在服务器运作的同时允许实用程序对表进行操作,将引起表的毁坏。了解怎样限制这种类型的交互作用以避免表毁坏是重要的。有关恰当使用这些程序的说明,请参阅第13章“数据库维护和修复”。

数据库的表示法

由MySQL管理的每个数据库都有自己的数据库目录,它们是数据目录的子目录,与所表示的数据库有相同的名称。例如,数据库my_db 对应于数据库目录DATA D I R/ my _ db。
这个表示法使得几个数据库级的语句的实现几乎是微乎其微的。CREATE DATA B A S E db _ name 使用只允许对MySQL服务器用户(服务器运行的UNIX 用户)进行访问的所有权和方式,并在数据目录中创建一个空目录db _ name。这等价于以服务器主机中的服务器用户的身份通过执行下列命令手工创建数据库:
% mkdir DATADIR/db_name 创建数据库目录
% chmod 700 DATADIR/db_name 使它仅对MySQL服务器用户可访问
通过空目录表示新数据库的方法与其他数据库系统完全不同,那些数据库系统甚至要为“空”数据库创建许多控制文件或系统文件。
DROP DATABASE 语句也很容易实现。DROP DATABASE db _ name 删除数据目录中的db _ name 目录以及其中的所有表文件。这个语句类似于下列命令:
%rm -rf DATA D I R / db _ name
其区别是,服务器只删除带有表的扩展名的文件。如果已经在该数据库目录中创建了其他的文件,服务器将使它们保持完整,并且不删除该目录本身。
SHOW DATABASE 只不过是对应位于数据目录中的子目录名称的一个列表。有些数据库系统需要保留一个列出所有需要维护的数据库的主表,但是,在MySQL中没有这样的结构。由于数据目录结构的简单性,数据库的列表是隐含在该数据目录的内容中的,像主表这样的
表可能会引起不必要的开销。

数据库表的表示法

数据库中的每个表在数据库目录中都作为三个文件存在:一个格式(描述)文件、一个数据文件和一个索引文件。每个文件的基名是该表名,扩展名指明该文件的类型。扩展名如表10 - 1所示。数据和索引文件的扩展名指明该表是否使用较老的ISAM 索引或较新的MyISAM 索引。

当发布定义一个表结构的CREATE TABLE tbl_name 语句时,服务器创建tbl_name. f r m文件,它包含该结构的内部编码。该语句还创建空的数据文件和索引文件,这些文件的初始信息表明没有记录和索引(如果CREATE TABLE 语句包含索引说明,则该索引文件将反映这些索引)。描述表的文件的所有权和方式被设置为只允许对MySQL服务器用户的访问。
当发布ALTER TABLE 语句时,服务器对tbl_name.frm 重新编码并修改数据文件和索引文件的内容以反映由该语句表明的结构变化。对于CREATE 和DROP INDEX 也是如此,因为服务器认为它们等价于ALTER TABLE 语句。DROP TABLE 删除代表该表的三个文件。
尽管可以通过删除数据库目录中的对应某个表的三个文件来删除该表,但不能手工创建或更改表。例如,如果my_db 是当前的数据库,DROP TABLE my_tbl 大致等价于下列命令:
% rm -f DATADIR/my_db_tbl.*
来自于SHOW TABLES my_db 的输出结果正是my_db 数据库目录中.frm 文件基名的一个列表。某些数据库系统维护一个列出了数据库中的所有表的登记。但MySQL不这样做,因为没有必要,这个“登记”隐含在了数据目录的结构中。

数据库和表命名中的操作系统约束

MySQL具有对数据库和表命名的一般规则:
名字可以由当前字符集中的字母数字字符以及下划线和美元符号(‘_’ 和‘$’)组成。
名字最长可达64 个字符。
但是,由于数据库和表的名字对应于目录和文件名,因此,对数据库运行的操作系统可以施加另外的约束。
首先,将数据库和表名限制为文件名中的合法字符。例如,按照MySQL的规则,名字中允许使用‘ $’,但是,如果操作系统不允许使用它,则不能在目录名或表名中使用。实际上,这与UNIX 或Windows 无关。可能会遇到的最大困难是在进行数据库管理时从外壳程序
中直接命名。例如,如果给某个数据库定义了诸如$my_db 的名字,该名字包括美元符号,对来自外壳程序命令行的该名字的任何引用都可由外壳程序解释为一个变量引用:
% ls $my_db
my_db:Undefined variable
如果这种情况发生,必须将‘ $’字符换码,或使用引号来取消其特殊的含义:
% ls $my_db
% ls '$my_db'
如果要使用引号,则应使用单引号。双引号不能取消对变量的解释。
第二,尽管MySQL允许数据库和表的名字最大长度为6 4个字符,但名字的长度也要受到操作系统所允许长度的限制。通常,这不是什么问题,尽管在UNIX 中您可能会进入有14个字符限制的旧版本System V-ish 系统中。在这种情况下,数据库名字的有效限制为14 个字符,表名的限制为10个字符,因为表示表的文件名称可用一个句点和三字符的扩展名终结。
第三,基础文件系统的大小写敏感性影响您对数据库和表的命名及引用。如果文件系统是区分大小写的(如UNIX),则my_tbl 和MY_TBL 这两个名字涉及不同的表。如果文件系统不是区分大小写的(如Windows),则my_tbl 和MY_TBL 是同一个表。您应当留意是否使用了UNIX 服务器来开发数据库,如果有可能的话,在某时应将该数据库移到Windows 服务器上。

系统性能的数据目录结构的含义

数据目录的结构易于理解,因为它使用了文件系统的层次结构的方式。同时,该结构具有特定的性能含义,尤其是关于打开表示数据库表文件的操作。
这种数据目录结构的一个后果是,由于表由多个文件来表示,因此每个打开的表都需要多个文件描述符,而不是一个。服务器智能化地高速缓存这些描述符,但是一个繁忙的服务器可能会很轻易地耗尽描述符资源,如果服务器同时为许多并发的客户机连接服务或运行引
用多个表的复杂查询的话。文件描述符在许多系统中都是匮乏的资源,尤其是将缺省的总进程(per- p r o c e s s)限制设置得相当低的系统。第11章“常规的MySQL管理”将提供有关估计所需描述符数量的信息,以及在需要时重新配置服务器或操作系统的信息。
由表自己的文件表示每个表的另一个后果是,表的打开时间随表的数量而增加。打开表的操作映射成由操作系统提供的文件打开操作,因此将受到系统的目录查找程序( d i r e c t o r y - lookup routine)效率的影响。通常这不是个问题,但是,如果在数据库中需要大量的表时,它则是个要考虑的问题。
例如,如果想要得到10 000 个表,则数据库目录中应该包含30 000 个文件。对于这么多的文件,将会引起由于文件打开操作所花费的时间而使运行速度降低( Linux ext2 和S o l a r i s 文件系统存在这个问题)。如果这个问题涉及到利害关系,则应根据应用程序的需要明智地重新考虑表的结构,从而重新组织这些表。应查看一下是否真的需要这么多的表,因为有时应用程序会不必要地繁殖许多表。为每个用户创建一个单个表的应用程序将导致许多表的产生,其实所有这些表都有相同的结构。如果您想将这些表合并成一个表,可以通过增加另一列以标识每行所使用的用户来达到目的。如果这能使表的数量明显减少,则会相应提高应用程序的性能。
在数据库设计阶段,您必须考虑这个特定的阶段对于一个给定的应用程序是否是值得的。不按上面所描述的方法来合并表的原因如下:
增大的磁盘空间的需求。合并表是为了减少所需表的数量(减少表打开的时间),但增加了另一列内容(增加磁盘空间的需求)。这是典型的空间与时间的折衷,您需要决定哪个因素更重要。如果认为速度极为重要,您或许愿意牺牲一点额外的磁盘空间。如果空间太紧张,则只能忍受使用多个表的时间。
安全性考虑。这些可能会约束您的能力或对表合并的愿望。每个用户分别使用单独的表的一个原因是:使只有拥有表级权限的用户才能对每个表进行访问。如果合并了表,则所有用户数据都将在同一个表中出现。
MySQL没有限制一个已知用户对特定行的访问的规定,因此,如果没有泄密访问控制就不能合并表。另一方面,如果所有的数据访问都由应用程序控制(用户不可能直接连接到服务器),则可以合并表并使用应用程序的逻辑强制合并后的行级访问。
MySQL对于表的大小有其自己内部的限制,但是,由于它将表表示为文件, MySQL还将受到文件尺寸最大值的限制,该最大值是由操作系统给出的。因此,有效的表尺寸最大值要小于MySQL的内部限制和系统文件尺寸的限制。
通常,随着时间的推移,对尺寸大小的约束将有所缓和。例如, IBM AIX4.1有2GB 文件大小的限制,但是在AIX4.2 中该限制值大约为6 4 G B。在MySQL中内部的表大小限制值也随着最新版本的出现而增加。在3.23 系列之前,内部的限制值为4 G B。从3 . 2 3系列起,该限制值大约为9 000 000太字节。表10-2 说明了MySQL内部的表大小限制和AIX 文件大小限制怎样相互作用来确定有效的表大小的最大值。类似的相互作用也可应用于其他的操作系统。


MySQL的状态文件

除数据库目录外,MySQL数据目录还包含许多状态文件。表10-3 概括介绍了这些文件。大多数状态文件的缺省名称从服务器主机名字中生成,在此表中表示为H O S T N A M E。
表10-3 MySQL状态文件

文件类型 缺省名 文件内容
进程ID HOSTNAME.pid 服务器进程ID
错误日志 HOSTNAME.err 启动和关闭事件和错误状态
常规日志 HOSTNAME.log 连接/断开事件和查询信息
更新日志 HOSTNAME.nnn 修改表的内容或结构的所有查询的文本

服务器在启动时将它的进程ID(PID )写入PID 文件,并在关闭时删除该文件。PID 文件是一种方法,用这种方法,其他的进程可以找到该服务器。例如,如果您在系统关闭时运行mysql.server 脚本来关闭MySQL服务器,则该脚本将检查PID 文件以确定它需要哪个进程来发送一个终止信号。
错误日志由safe_mysqld 产生,作为服务器标准错误输出结果的重定向,它包含服务器写入stderr 的所有消息。这意味着仅当通过调用safe_mysqld 启动服务器时,错误日志才存在(总之,这是启动服务器的首选方法,因为,如果由于一个错误使错误日志存在,则
s a f e _ mysqld将重新启动服务器)
常规日志和更新日志是可选的,可以用--log 和--log-update 服务器选项开启需要的日志类型。
常规进程提供有关服务器运作的常规信息:谁从哪里进行了连接,以及他们发布了什么查询。更新日志也提供查询信息,但仅仅是修改过的数据库内容的查询信息。更新日志的内容是一些SQL 语句,这些语句可以通过将它们输入到mysql客户机程序来运行。如果出现崩
溃且必须转到备份文件时,更新日志将是有用的,因为您能够通过将更新日志输入到服务器来重复这些自崩溃以来所完成的更新操作。这将使得数据库恢复到崩溃发生时所处的状态上。
下面是一个实例,它是作为一个短客户机会话的结果出现在常规日志中的信息中的,这个会话在test 数据库中创建一个表,并插入一行到该表中,然后删除该表:

常规日志包含日期和时间、服务器线程ID、事件类型以及特定事件信息的列。
同一个会话出现在如下的更新日志中:

对于更新日志,日志的扩展格式是可用的,即使是用--log - long - format 选项。扩展的日志提供有关谁何时发布查询的信息。当然,这将使用更多的磁盘空间,但是,如果您不将更新日志的内容与常规日志中的连接事件相联系就想知道谁正在做什么的话,扩展日志或许是可用的。
对于刚才显示出的会话,扩展日志将产生下列信息:

确保日志文件的安全且不被用户任意读取是个好注意。常规日志和更新日志都包含有诸如口令这样的敏感信息,这是因为它们包含了查询的文本。下面是您不想让任何人都能读取的日志项,因为它显示了root 用户的口令:

有关检查可设置数据目录许可权的信息,请参阅第12 章。数据目录安全的简短指令由下列命令组成:
% chmod 700 DATADIR
以拥有该数据目录的UNIX 用户身份来运行此命令。还要确保服务器以该用户身份运行,否则此命令不仅将其他用户排斥在该数据目录之外(您想要的),还将阻止服务器访问您的数据库(您不要的)。
状态文件出现在数据目录的最高级,就像数据库目录一样,因此您可能会想到那些文件的名字是否会相互混淆或者被误认为是数据库名(例如,当服务器正在执行S H O W DATABASE 语句时)。答案是:不会的。状态和日志信息存储在文件中,而数据库是目录,因此可执行程序可以将它们与一个简单的stat() 调用相区别(是服务器告诉它们怎样区分的)。如果您正在监视数据目录,则可以通过使用ls -l 将状态文件从数据库目录中区分开来,并且检查该模式信息的第一个字符以查看它是‘ -’还是‘d’:

您还可以通过查看名字而简单地告之:所有状态文件名都包含一个句点,但是数据库目录名没有句点(句点不是数据库名的合法字符)。
有关日志文件维护和循环技术的信息,请参阅第11章的内容。