每個數據庫對應該數據目錄下的一個目錄。
數據庫中的表對應數據庫目錄中的文件。
數據目錄還包含幾個由服務器生成的狀態文件,如日志文件。這些文件提供了關於服務器運作的重要信息,對管理員是有用的,尤其是當問題出現且試圖確定問題的原因時特別有用。例如,如果某個特定的查詢毀壞了數據庫,您可以通過檢查日志文件來識別這個討厭的查詢。
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狀態文件 文件類型缺省名文件內容進程IDHOSTNAME.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’:
您還可以通過查看名字而簡單地告之:所有狀態文件名都包含一個句點,但是數據庫目錄名沒有句點(句點不是數據庫名的合法字符)。