文件
分析構成MySQL數據庫和InnoDB存儲引擎的各種類型文件。
參數文件:告訴MySQL實例啟動時在哪里可以找到數據庫文件,並且指定某些初始化參數,這些參數定義了某種內存結構的大小等設置,還會介紹各種參數的類型。
日志文件:用來記錄MySQL實例對某種條件做出相應時寫入的文件,如錯誤日志文件、二進制日志文件、慢查詢日志文件、查詢日志文件等。
socket文件:當用UNIX域套接字方式進行連接時需要的文件。
pid文件:MySQL實例的進程ID文件。
MySQL表結構文件:用來存放MySQL表結構定義文件。
存儲引擎文件:因為MySQL表存儲引擎的關系,每個存儲引擎都會有自己的文件來保存各種數據。這些存儲引擎真正存儲了記錄和索引等數據。
參數文件
什么是參數
可以把數據庫參數看成一個鍵/值(key/value)對。我們將這個參數設置為1G, 即innodb_buffer_pool_size=1G。這里的"鍵"是innodb_buffer_pool_size,“值”是1G,這就是鍵值對。
可以使用SHOW VARIABLES查看數據庫中的所有參數,也可以通過LIKE來過濾參數名。
show variables like 'innodb_buffer%'\G;
參數類型
動態參數意味着可以在MySQL實例運行中進行更改,靜態參數說明在整個生命周期內部都不得進行更改,就好像是只讀的。
可以通過set命令對動態參數進行更改。
- 動態參數
可以看到read_buffer_size從262KB調整到8KB,而用戶登錄看到的全局的read_buffer_size的值依然是262KB,也就是僅在本回話中才是這個數值。
這次將read_buffer_size全局值更改為80KB,而當前會話的read_buffer_size的值依然還是8KB, 對變量的全局值進行了修改,在這次的實例生命周期內都有效,但MySQL本身不會對參數文件進行修改。在下次啟動MySQL啟動時,還是會讀取參數文件。
若用戶想在數據庫實例下一次啟動時該參數還是保留為當前的修改的值,那么用戶必須去修改參數文件。
- 靜態參數
若對靜態參數進行修改,會得到錯誤。
日志文件
錯誤日志(error log)
錯誤日志文件是對MySQL的啟動、運行、關閉過程進行了記錄。
MySQL DBA在遇到問題時應該首先查看該文件以便定位問題。該文件不僅記錄了所有的錯誤信息,也記錄一些警告信息或正確的信息。
慢查詢日志(show query log)
慢查詢日志用來幫助DBA定位可能存在問題的SQL語句,從而進行SQL語句層面的優化,
- long_query_time:
在MySQL啟動時設置一個閾值,將運行時間操作該閾值的所有SQL語句記錄到慢查詢日志文件中。DBA每天或每過一段時間對其進行檢查,確認是否有SQL語句需要進行優化。該閾值通過參數long_query_time進行設置。默認10秒。只有大於這個值才會被記錄。
另外一個和慢日志有關的參數log_queries_not_using_indexes.如果運行的SQL語句沒有使用索引,則MySQL數據庫同樣會將這條SQL語句記錄到慢查詢日志文件中。
- 慢查詢表slow_log:
- long_query_io:
查詢日志(log)
查詢日志可以使用general_log表,使用方法和slow_log相同
二進制日志(binlog)
二進制文件記錄了對MySQL數據庫執行的更改操作,但是不包括SELECT和SHOW這類操作。因為這類操作對數據本身沒有修改,然而,若操作本身並沒有導致數據庫發生變化,那么該操作也會寫入二進制。
二進制查詢的作用:
Socket文件
Pid文件
Pid文件是指當MySQL實例啟動時,會將自己的進程ID寫入PID文件中。
表結構定義文件
InnoDB存儲引擎文件
本節將介紹與InnoDB存儲引擎密切的相關文件。
1.表空間文件
InnoDB采用將存儲的數據按表空間(tablespace)進行存放和設計,在默認配置下會有一個10MB大小的文件,名為ibdata1文件,該文件就是默認的表空間文件(tablespace file),用戶可以通過參數innodb_data_file_path進行設置。
用戶可以通過多個文件組成一個表空間,同時制定文件的屬性:
innodb_data_file_path=/db/ibdata1:2000M;/dr2/db/ibdata2:2000M:autoextend
表Profile、t1和t2都是基於InnoDB存儲的表,由於設置參數inondb_file_per_table=on, 因此產生了單獨的.idb獨立表空間文件。單獨的表空間文件僅僅存儲該表的數據、索引和插入緩沖BITMAP等信息。其余的信息還存放在默認的表空間中。
2.重做日志文件
重做日志文件(redo log file):
重做日志文件對InnoDB存儲引擎至關重要,它們記錄了對於InnoDB存儲引擎的事務日志。
在默認情況下,在InnoDB存儲引擎的數據目錄下會有兩個名為ib_logfile0和id_logfile1的文件。在MySQL官方手冊中將其稱為Innodb存儲引擎的日志文件,更准確的定義是重做日志文件(redo log file)。
當實例或介質失敗,重做日志文件就能派上用場。如,數據庫主機掉電介質失敗,InnoDB存儲引擎會使用重做日志恢復到掉電前的水平,以此來保證數據的准確性。
每個InnoDB存儲引擎至少有1個重做日志文件組(group),每個文件組至少有2個重做日志文件,如默認的id_logfile0和ib_logfile1。為了得到更高的可靠性,用戶可以設置多個的鏡像日志組(mirrored log groups),將不同的文件組放在不同的磁盤上,以此提高重做日志的高可用性。在日志組中每個重做日志文件的大小一致,並以循環寫入的方式運行。InnoDB存儲引擎先寫重做日志文件1,當達到文件的最后時,會切換至重做日志文件2,再當重做日志文件2也被寫滿時,會再切換到重做日志文件1。
-
innodb_log_file_size
-
innodb_log_file_in_group
-
innodb_mirrored_log_groups
-
innodb_log_group_home_dir
總結
表
索引組織表
在InnoDB存儲引擎中,表都是根據主鍵順序組織存放的,這種存儲方式的表稱為索引組織表(index organized table) 。在InnoDB存儲引擎表中,每張表都有個主鍵(Primary Key),如果在創建表時沒有顯式地定義主鍵,則InnoDB存儲引擎會按照如下方式選擇或創建主鍵盤:
選擇或者創建主鍵的方式:
- 首先判斷表中是否有唯一的非空索引(unique not null), 如果有,則該列即為主鍵。
- 如果不符合上述條件,InnoDB存儲引擎自動創建一個6字節大小的指針。
當表中有多個非空唯一索引時,InnoDB存儲引擎將選擇建表時第一個非空索引作為主鍵。
注意:主鍵的選擇根據的是定義索引的順序,而不是建表時的順序。
_rowid可是顯示表的主鍵,因此通過上述查詢可以找到表z的主鍵。此外,雖然c d 列都是非空唯一索引,都可以作為主鍵的候選,但是在定義的過程中,由於d列首先定義唯一索引,故InnoDB存儲引擎作為主鍵。
InnoDB邏輯存儲結構
表空間
表空間是Innodb存儲結構的最高層,所有的數據都存放在表空間中。如果用戶啟用了參數innodb_file_per_table,則每張表內數據可以單獨放到表空間內。
如果啟用了innodb_file_per_table的參數,需要注意的是每張表的表空間內存放的只是數據、索引和插入緩存Bitmap頁,其他類的數據,如回滾(undo)信息,插入緩沖索引頁,系統事務信息,二次寫緩沖(double write buffer)等還是存放在原來的共享表空間ibdata1內。
這也說明了,即使啟用了參數innodb_file_per_table之后,共享表空間還是會不斷增大。
另外要注意的是,即使對事務進行rollback, ibdata1這個表也並不會縮減至原來大小。
段
區
區的大小為1MB, 區是由連續頁組成的,為了保證區中頁的連續性,InnoDB一次會從磁盤中申請4~5個區。默認情況下存儲引擎頁的大小是16KB,即一個區中有連續64個頁。
碎片頁:(fragment page)
用戶在啟用了參數innodb_file_per_table后,創建的表默認大小是96KB。區中是64個連續的頁。每個段開始,先用32頁大小的碎片頁來存放數據,在使用完這些頁之后才是64個連續頁的申請,一次來節省空間。
頁
行
Innodb行記錄格式
Innodb存儲引擎以行的形勢存儲。這意味着頁中保存着表中一行行的數據。
查看當前表使用的行格式:
Compact行記錄格式
create table mytest( t1 varchar(10), t2 varchar(10), t3 char(10), t4 varchar(10) )engine=innodb row_format=compact;
Redundant行記錄格式
create table mytest2 engine=Innodb row_format=redundant as select * from mytest;
行溢出數據
InnonDB存儲引擎可以將一條記錄中的某些數據存儲在真正的數據頁面之外。
VARCHAR(N)中的N指的是字符長度。而文檔中說明VARCHAR類型最大支持65535,單位是字節。
需要注意的是,MySQL官方手冊中定義的 65535長度是指所有VARCHAR列的長度總和,如果列的長度總和超出這個長度,依然無法創建。
Compressed 和 Dynamic行記錄格式
CHAR的行結構存儲
從MySQL4.1版本開始,CHAR(N)中N指的是字符的個數!而不是之前版本中的字節長度。
在不同的字符集下,CHAR類型列內部存儲的可能不是定長的數據。gbk下中文2個字符,utf-8下每個中文3個字節。
創建一個表,指定表中字段類型為2字符
CREATE TABLE j(a char(2))charset=utf8 engine=innodb;
insert into j select 'ab';
insert into j select '我們';
insert into j select 'a';
InnoDB存儲引擎內部對CHAR類型在多字節字符集類型的存儲。CHAR類型被明確視為了變長字符類型,對於未能占滿長度的字符還是填充0x20。
Innodb數據頁結構
頁是Innodb存儲管理數據引擎的最小單位。
數據頁由以下7部分組成:
File Header用來記錄頁的一些頭信息,由8部分組成,共占38字節。
Page Header接着File Header部分是Page Header, 該部分用來記錄數據頁的狀態信息,由14部分組成,共占用56個字節。
Infimum 和 Supremum Record
User Record 和 Free Space
User Record 實際存儲行記錄的內容
InnoDB存儲引擎表總是B+索引組織的
Free Space很明顯指的就是空閑空間,同樣也是個鏈表數據結構。在一條記錄被刪除后,該空間會被加入到空閑鏈表中
File Trailer
Named File Format機制
InnoDB存儲引擎通過Named File Format機制解決不同版本下頁結構兼容性問題。
約束
數據完整性
關系型數據庫和文件系統不同,關系數據庫能保證存儲數據的完整性,不需要應用程序的控制,而文件系統一般需要在程序端進行控制。當前幾乎所有的關系型數據庫都提供了約束機制,該機制保證了數據的完整性。
數據庫的完整性有如下三種:
實體完整性:
保證表中有一個主鍵盤。在InnoDB存儲引擎表中,用戶可以通過定義Primary Key或Unique Key約束來保證實體的完整性。用戶還可以通過編輯一個觸發器來保證實體完整性。
域完整性:
保證每列的值滿足特定的條件。在InnoDB存儲引擎表中,域完整性可以通過以下幾個途徑來保證:
- 選擇合適的數據類型確保一個數據值滿足特定條件
- 外鍵(Foreign Key)約束
- 編寫觸發器
- 還可以考慮用DEFAULT約束作為強制域完整性的一個方面
參照完整性:
參照完整性保證兩個表之間的關系。InnoDB支持外鍵,因此允許用戶定義外鍵以強制參照完整性,也可以通過編寫觸發器以強制執行。
對於InnoDB存儲引擎本身,提供了以下幾種約束:
Primary Key
Unique Key
Foreign Key
Default Key
Not NULL
約束的創建和查找
約束創建時可采用如下兩種方式:
- 表建立時就進行約束定義
- 利用ALTER TABLE命令進行創建約束
important:
-
Foreign key約束並不僅僅可以與另一表中的Primary key相連接,還可以定義為應用另一表的unique約束
。Foreign key約束可以包含空值,但是如果任何組合Foreign key約束的列包含空值,則將跳過組成foreign key約束的所有值的驗證。若要確保驗證了組合foreign key約束的所有值,請將所有參與列定義為NOT NULL。 -
unique的數據項可以為空,外鍵的值也可以為空,外鍵也可以關聯unique的數據
創建u表和p表,p表存在外鍵,引用主鍵u
create table u(id int, name varchar(20), id_card char(18), primary key(id),unique key(name));
create table p(id int,u_id int,primary key(id),foreign key(u_id) references u(id));
在u表數據為空的情況下,向p表中插入數據,可以發現報錯。
在u表數據存在1,向p表中插入數據,外鍵盤數據也為1,可以發現成功!
那么如果保證在主鍵不存在的情況下,向外鍵表中插入值呢?
mysql中有一個參數FOREIGN_KEY_CHECKS
利用這個參數,設置
set FOREIGN_KEY_CHECKS=0
此時可以執行p表添加操作
添加完成后,將FOREIGN_KEY_CHECKS改為1即可
set FOREIGN_KEY_CHECKS=1
對錯誤數據的約束
MySQL數據庫允許非法的或不正確的數據插入或更新,又或者可以在數據庫內部將其轉化為一個合法的值,如向NOT NULL的字段插入一個NULL值,Mysql會將其更改為0再插入。
set sql_mode='STRICT_TRANS_TABLES'
ENUM和SET約束
create table a(id int,sex enum('male','female'));
insert into a_enum select 1,'female';
show variables like 'sql_mode'\G;
約束和索引的區別
觸發器與約束
觸發器的作用是在執行INSERT DELETE 和 UPDATE命令之前或之后自動調用SQL命令或存儲過程。
創建觸發器的命令是CREATE TRIGGER,只有具備Super權限的MySQL數據庫用戶才可以自行這條命令:
CREATE
[DEFINER={user|CURRENT_USER}]
TRIGGER trigger_name BEFORE|AFTER INSERT|UPDATE|DELETE
ON tb1_name FOR EACH ROW trigger_stmt
最多可以為一個表建立6個觸發器。當前MySQL只支持FOR EACH STATEMENT 的觸發方式。
DELIMITER $$
CREATE TABLE usercash_err_log BEFORE UPDATE ON usercash(
FOR EACH ROW
BEGIN
IF new.cash-oil.cash > 0 THEN
INSERT INTO usercash_err_log
SELECT old.userid, old.cash, new.cash,USER(),NOW();
SET new.cash = old.cash;
END IF;
END;
$$
)
DELIMITER $$
上述例子首相穿件一張usercash_err_log來記錄錯誤數值更新的日志,然后創建了進行約束操作的觸發器tgr_usercash_update,其類型為BEFORE。 觸發器首先判斷新、舊值之間的差值,在正常情況下消費總是減的,新值應該總是小於原來的值,因此大於原值的數據被判斷為非法的輸入,將cash值設定為原來的值,並將非法的數據更新插入表usercash_err_log.
外鍵約束
外鍵用來保證參照完整性,MySQL存儲引擎完整支持外鍵約束。
外鍵定義如下:
用戶可以在執行CREATE TABLE時就添加外鍵,也可以在表創建后通過ALTER TABLE命令來添加。
CREATE TABLE parent(
id INT NOT NULL,
PRIMARY KEY(id)
)ENGINE = INNODB;
CREATE TABLE child(
id INT, parent_id INT,
FOREIGN KEY(parent_id) REFERENCES parent(id)
)ENGINE=INNODB;
對子表所做的操作,可定義的子表操作有:
CASCADE
SET NULL
NO ACTION
RESTRICT
對於參照完整性約束,外鍵能起到一個非常好的作用。但是對於數據的導入時,外鍵導致在外鍵約束的檢查上花費大量時間。因為MySQL數據庫的外鍵是即時檢查的,所以對導入的每一行都會進行外鍵檢查。
但是用戶可以關閉外鍵檢查:
SET foreign_key_checks = 0; SET foreign_key_checks = 1;
視圖
在 MySQL數據庫中,視圖(View)是一個命名的虛表,它由一個SQL查詢來定義,可以當做表使用。
與持久表(permanent table)不同的是,視圖中的數據沒有實際的物理存儲。
視圖的作用
創建視圖
修改視圖
create view v_t as select * from t where id<10;
insert into v_t select 20;
select * from v_t;
上面的例子中,創建了一個id<10的視圖v_t。但之后向視圖里插入了id為20的值,插入沒有報錯。但是用戶查詢還是沒能查到數據。接着更改視圖定義WITH CHECK OPTION選項。可以發現錯誤。
alter view v_t as select * from t where id<10 with check option;
insert into v_t select 20;
show tables\G;
物化視圖
物化視圖可以用於預先計算並保存多表的鏈接(JOIN)或聚集(GROUP BY)等耗時較多的SQL操作。
物化視圖再SQL Server數據庫中,稱這種視圖為索引視圖。
分區表
對於OLAP應用,分區可以提高查詢性能。而對於OLTP分布,並不一定有用。
通過以下命令來查看當前數據庫是否啟用了分區功能:
SHOW VARIABLES LIKE '%partition%'\G;
SHOW PLUGINS\G;
當前MySQL數據庫支持以下幾種類型的分區:
參考如下: