The MySQL data directory contains all of the databases and tables managed by the server. In general, these are organized into a tree structure that is implemented in straightforward fashion by taking advantage of the hierarchical structure of the UNIX or Windows file systems:
The exception to this hierarchical implementation of databases and tables as directories and files is that the InnoDB table handler stores all InnoDB tables from all databases within a single common tablespace. This tablespace is implemented using one or more large files that are treated as a single unified data structure within which tables and indexes are represented. The InnoDB tablespace files are stored in the data directory by default. The data directory also may contain other files:
How the MySQL Server Provides Access to DataWhen MySQL is used in the usual client/server setup, all databases under the data directory are managed by a single entity the MySQL server mysqld. Client programs never manipulate data directly. Instead, the server provides the sole point of contact though which databases are accessed, acting as the intermediary between client programs and the data they want to use. Figure 10.1 illustrates this architecture. Figure 10.1. How the MySQL server controls access to the data directory.When the server starts up, it opens any log files that you request it to maintain and then presents a network interface to the data directory by listening for various types of network connections. (Details of how the server listens are presented in Chapter 11.) To access data, client programs establish a connection to the server and then communicate requests as SQL queries to perform the desired operations for example, creating a table, selecting records, or updating records. The server performs each operation and sends back the result to the client. The server is multi-threaded and can service multiple simultaneous client connections. However, because update operations are performed one at a time, the practical effect is to serialize requests so that two clients can never change a given record at exactly the same time. If you're running an application that uses the embedded server, a slightly different architecture applies, because there is only one "client" that is, the application into which the server is linked. In this case, the server listens to an internal communication channel rather than to network interfaces. Nevertheless, it's still the embedded server part of the application that manages access to the data directory, and it's still necessary to coordinate query activity arriving over multiple connections if the application happens to open several connections to the server. Under normal conditions, having the server act as the sole arbiter of database access provides assurance against the kinds of corruption that can result from multiple processes accessing the database tables at the same time. Nevertheless, administrators should be aware that there are times when the server does not have exclusive control of the data directory:
How MySQL Represents Databases in the File SystemEach database managed by the MySQL server has its own database directory. This exists as a subdirectory of the data directory, with the same name as the database it represents. For example, a database mydb corresponds to the database directory DATADIR/mydb. This representation allows several database-level statements to be almost trivial in their implementation. SHOW DATABASES is essentially nothing more than a list of the names of the directories located within the data directory. Some database systems keep a master table that lists all the databases maintained, but there is no such construct in MySQL. Given the simplicity of the data directory structure, the list of databases is implicit in the contents of the data directory, and such a table would be unnecessary overhead. CREATE DATABASE db_name creates an empty directory db_name in the data directory. Under UNIX, the directory is owned by and accessible only to the login account that is used for running the server. This means that the CREATE DATABASE operation is equivalent to executing the following shell commands on the server host while logged in under that account: % cd DATADIR % mkdir db_name % chmod u=rwx,go-rwx db_name The minimal approach of representing a new database by an empty directory contrasts with other database systems that create a number of control or system files even for an "empty" database. The DROP DATABASE statement is implemented nearly as easily. DROP DATABASE db_name removes the db_name directory in the data directory, along with any table files contained within it. This is almost the same as executing the following commands on UNIX: % cd DATADIR % rm -rf db_name or the following commands on Windows: C:\> cd DATADIR C:\> del /S db_name The differences between a DROP DATABASE statement and the shell commands are as follows:
How MySQL Represents Tables in the File SystemMySQL supports handlers for several types of database tables: ISAM, MyISAM, MERGE, BDB, InnoDB, and HEAP. Every table in MySQL is represented on disk by at least one file, which is the .frm file that contains a description of the table's structure. For most table types, there are also other files that contain the data rows and index information. These vary according to the table type, as outlined in the following discussion. (The descriptions here focus primarily on the characteristics of the table types as they are stored on disk. For information about how these types differ in features and behavior, see Chapter 3, "MySQL SQL Syntax and Use.") ISAM TablesThe original table type in MySQL is the ISAM type. MySQL represents each ISAM table by three files in the database directory of the database that contains the table. The files all have a basename that is the same as the table name and an extension that indicates the purpose of the file. For example, a table named mytbl is represented by three files:
MyISAM TablesMySQL 3.23 introduced the MyISAM table type as the successor to the ISAM type, which now is considered pretty much obsolete. Like the ISAM handler, the MyISAM handler represents each table by three files, using the extensions .frm, .MYD, and .MYI for the description, data, and index files, respectively. MERGE TablesA MERGE table is a logical construct. It represents a collection of identically structured MyISAM tables that are treated for query purposes as a single larger table. Within a database directory, a MERGE table is represented by its .frm file and a .MRG file that is nothing more than a list of the names of the table's constituent MyISAM tables, one name per line. One implication of this representation is that it's possible to change the definition of a MERGE table by flushing the table cache with FLUSH TABLES and then directly editing the .MRG file to change the list of MyISAM tables named there. (I'm not sure I'd recommend actually doing this, though.) BDB TablesThe BDB handler represents each table by two files, the .frm description file and a .db file that contains the table's data and index information. InnoDB TablesThe preceding table types all are represented using files that each are uniquely associated with a single table. InnoDB tables are handled in a somewhat different way. The only file that corresponds directly to a given InnoDB table is the .frm table description file, which is located in the directory for the database to which the table belongs. The data and indexes for all InnoDB tables are managed together within a single unified tablespace. Typically, the tablespace itself is represented by one or more large files in the data directory. These components of the tablespace form a logically contiguous storage area equal in size to the sum of the sizes of the individual files. HEAP TablesHEAP tables are in-memory tables. Because the server stores a HEAP table's data and indexes in memory rather than on disk, the table is not represented in the file system at all, other than by its .frm file. How SQL Statements Map onto Table File OperationsEvery table type uses a .frm file to store the table description, so the output from SHOW TABLES db_name is the same as a listing of the basenames of the .frm files in the database directory for db_name. Some database systems maintain a registry that lists all tables contained in a database. MySQL does not because it is unnecessary; the "registry" is implicit in the structure of the data directory. To create a table of any of the types supported by MySQL, you issue a CREATE TABLE statement that defines the table's structure. For all table types, the server creates a .frm file that contains the internal encoding of that structure. The server also creates any other files that are associated with tables of the given type. For example, it creates .MYD and .MYI data and index files for a MyISAM table or a .db data/index file for a BDB table. For InnoDB tables, the handler initializes data and index information for the table within the InnoDB tablespace. Under UNIX, the ownership and mode of any files created to represent the table are set to allow access only to the account that the server runs as. When you issue an ALTER TABLE statement, the server re-encodes the table's .frm file to reflect the structural change indicated by the statement and modifies the contents of the data and index files likewise. This happens for CREATE INDEX and DROP INDEX as well because they are handled by the server as equivalent ALTER TABLE statements. Altering an InnoDB table causes the handler to modify the table's data and indexes within the InnoDB tablespace. DROP TABLE is implemented by removing the files that represent the table. Dropping an InnoDB table also causes any space associated with the table in the InnoDB tablespace to be marked as free. For some table types, you can remove a table manually by removing the files in the database directory to which the table corresponds. For example, if mydb is the current database and mytbl is an ISAM, MyISAM, BDB, or MERGE table, DROP TABLE mytbl is roughly equivalent to the following commands on UNIX: % cd DATADIR % rm -f mydb/mytbl.* or to the following commands on Windows: C:\> cd DATADIR C:\> del mydb\mytbl.* For an InnoDB or HEAP table, parts of the table are not represented within the file system in discrete files, so DROP TABLE does not have a file system command equivalent. For example, the .frm file is the only file uniquely associated with an InnoDB table. Removing that file will leave the table data and indexes "stranded" within the InnoDB tablespace. Operating System Constraints on Database and Table NamingMySQL has general rules for naming databases and tables. The rules are listed in detail in Chapter 3 but can be summarized briefly as follows:
However, because names of databases and tables correspond to names of directories and files, the operating system on which a server runs may impose additional constraints that stem from file system naming conventions:
One way to deal with the issue of case sensitivity is to always name your databases and tables with a given lettercase. Another is to set the lower_case_table_names server variable to 1, which has two effects:
The result of these actions is that names are not treated as case sensitive. However, there are two caveats you should keep in mind with respect to use of the lower_case_table_names variable. First, it does not apply to database names until MySQL 4.0.2; prior to that it applies only to table names. Second, you should enable this variable before you start creating databases or tables, not after. If you create names that include uppercase characters and then set the variable, it will not have the desired effect because then you will already have names stored on disk that are not entirely lowercase. To avoid this problem, rename any databases or tables with names that contain uppercase characters to names that are entirely lowercase before enabling the variable. Factors That Affect Maximum Table SizeTable sizes in MySQL are bounded, but sizes are limited by a combination of factors, so it is not always a simple matter to determine precisely what the bounds are. Factors that affect table size are as follows:
To determine the actual table size you can achieve, you must consider all applicable factors. The effective maximum table size likely will be determined by the smallest of those factors. Suppose you want to create a ISAM table. MySQL will allow the data and index files to reach 4GB. But if your operating system imposes a size limit on files of 2GB, that will be the effective limit for the table files. On the other hand, if your system has large file support, files can be bigger than 4GB and then the determining factor on table size will be MySQL's internal 4GB limit. With respect to InnoDB tables, one point to keep in mind is that all such tables must fit within the InnoDB tablespace. If you have a single InnoDB table, it can be as large as the tablespace. But if, as is more likely, you have many InnoDB tables, they all share the same space and thus each is constrained in size not only by the size of the tablespace but also by how much of the tablespace is allocated to other tables. Any individual InnoDB table can grow as long as the tablespace is not full. Conversely, when the tablespace fills up, no InnoDB table can grow any larger until you add another component to the tablespace to make it bigger. (As of MySQL 3.23.50, you can make the last tablespace component auto-extending, so that it will grow as long as it does not exceed the file size limit of your system and disk space is available. See Chapter 11 for details on tablespace configuration.) Implications of Data Directory Structure for System PerformanceThe structure of the MySQL data directory is easy to understand because it uses the hierarchical structure of the file system in such a natural way. At the same time, this structure has certain performance implications, particularly regarding operations that open the files that represent database tables. One consequence of the data directory structure is that for table handlers that represent each table using multiple files, an open table can require multiple file descriptors, not just one. The server caches descriptors intelligently, but a busy server can easily use up lots of them while servicing many simultaneous client connections or executing complex queries that reference several tables. This can be a problem, because file descriptors are a scarce resource on many systems, particularly those that set the default per-process descriptor limit fairly low. Another effect of representing each table by its own files is that table-opening time increases with the number of tables. Operations that open tables map onto the file-opening operations provided by the operating system and, as such, are bound by the efficiency of the system's directory-lookup routines. Normally this isn't much of an issue, but it is something to consider if you'll need large numbers of tables in a database. For example, a MyISAM table is represented by three files. If you want to have 10,000 MyISAM tables, your database directory will contain 30,000 files. With that many files, you may notice a slowdown due to the time taken by file-opening operations. (Linux ext2 and Solaris file systems are subject to this problem.) If this is cause for concern, you might want to think about using a type of file system that is highly efficient at dealing with large numbers of files. For example, ReiserFS exhibits good performance even with large numbers of small files. If that is not possible, it may be necessary to reconsider the structure of your tables in relation to the needs of your applications and reorganize your tables accordingly. Ask whether or not you really require so many tables; sometimes applications multiply tables needlessly. An application that creates a separate table per user results in many tables, all of which have identical structures. If you wanted to combine the tables into a single table, you might be able to do so by adding another column identifying the user to which each row applies. If this significantly reduces the number of tables, the application's performance improves. As always in database design, you must consider whether this particular strategy is worthwhile for a given application. Reasons not to combine tables in the manner just described are as follows:
Another way to create many tables without requiring so many individual files is to use InnoDB tables. The InnoDB handler associates only a .frm file uniquely with each table and stores the data and index information for all InnoDB tables together in the InnoDB tablespace. This minimizes the number of disk files needed to represent the tables, and it also substantially reduces the number of file descriptors required for open tables. InnoDB needs only one descriptor per component file of the tablespace (which is constant during the life of the server process) and briefly a descriptor for any table that it opens while it reads the table's .frm file. MySQL Status and Log FilesIn addition to database directories, the MySQL data directory contains a number of status and log files, as summarized in Table 10.1. The default location for these files is the server's data directory, and the default name for each of them is derived using the server host name, denoted as HOSTNAME in the table.
The Process ID FileThe server writes its process ID (PID) into the PID file when it starts up and removes the file when it shuts down. The PID file is the means by which a server allows itself to be found by other processes. For example, if the operating system runs the mysql.server script at system shutdown time to shut down the MySQL server, that script examines the PID file to determine which process it needs to send a termination signal to. The MySQL Log FilesMySQL can maintain a number of different log files. Most logging is optional; you can use server startup options to enable just the logs you need and also to specify their names if you don't like the defaults. This section describes the log files briefly. For more information about the logs and the options that control the server's logging behavior, see Chapter 11. The general log provides general information about server operation: who is connecting from where and what queries they are issuing. The update log provides query information, too, but only for queries that modify database contents. The contents of the update log are written as SQL statements that can be executed by providing them as input to the mysql client. The binary update log is similar to the update log but is represented in a more efficient binary format. The accompanying binary log index file lists which binary log files the server currently is maintaining. Update and binary update logs are useful if you have a crash and must revert to backup files because you can repeat the updates performed after the backup was made by feeding the logs to the server. This allows you to bring your databases up to the state they were in when the crash occurred. This procedure is described in more detail in Chapter 13. The binary logs are also used if you set up replication servers because they serve as a record of the updates that must be transmitted from a master server to slave servers. Here is a sample of the kind of information that appears in the general log as the result of a short client session that creates a table in the test database, inserts a row into the table, and then drops the table: 020727 15:00:17 1 Connect sampadm@localhost on test 2 Query CREATE TABLE mytbl (val INT) 2 Query INSERT INTO mytbl VALUES(1) 2 Query DROP TABLE mytbl 2 Quit The general log contains columns for date and time, server thread (connection) ID, event type, and event-specific information. For any line that is missing the date and time fields, the values are the same as for the previous line that does have them. (In other words, the server logs the date and time only when they change from the previously logged date and time.) The same session appears in the update log as follows. The statements include terminating semicolons, allowing them to be given as input to the mysql program should the updates need to be repeated for a recovery operation. use test; CREATE TABLE mytbl (val INT); INSERT INTO mytbl VALUES(1); DROP TABLE mytbl; For the update log, an extended form of logging is available by using the --log-long-format option. Extended logging provides information about who issued each query and when. This uses more disk space, of course, but may be useful if you want to know who is doing what without trying to correlate update log contents with the connection events in the general log. For the session just shown, extended update logging produces the following information: # Time: 020727 15:00:17 # User@Host: sampadm[sampadm] @ localhost [] use test; CREATE TABLE mytbl (val INT); # User@Host: sampadm[sampadm] @ localhost [] INSERT INTO mytbl VALUES(1); # User@Host: sampadm[sampadm] @ localhost [] DROP TABLE mytbl; The extra information is written using lines that begin with '#' so that they are interpreted as comments if you feed the log to mysql for execution by the server. The error log contains a record of diagnostic information produced by the server when exceptional conditions occur. It's useful if the server fails to start up or exits unexpectedly because it often will contain the reason why. Logs can grow quite large, so it's important to make sure they don't fill up your file system. You can expire the logs periodically to keep the amount of space that use within bounds. For information on log file maintenance, see Chapter 11. It's a good idea to make sure your log files are secure and not readable by arbitrary users because they may contain the text of queries that include sensitive information, such as passwords. For example, the following log entry displays the password for the root user; it's certainly not the kind of information you want just anyone to have access to: 020727 15:47:24 4 Query UPDATE user SET Password=PASSWORD('secret') WHERE user='root' The logs are written to the data directory by default, so securing your logs is a matter of securing the data directory against being accessed through login accounts other than that of the MySQL administrator. A detailed procedure for this is presented in Chapter 12, "Security." |