mysql dba系統學習(20)mysql儲存引擎MyISAM
mysql儲存引擎MyISAM
1,建立myisam表
mysql> create table t (id int , name varchar(30) , msg varchar(100)) engine = MyISAM;
mysql> show table status like "t" G ;
*************************** 1. row ***************************
Name: t
Engine: MyISAM
Version: 10
Row_format: Dynamic
Rows: 0
Avg_row_length: 0
Data_length: 0
Max_data_length: 281474976710655
Index_length: 1024
Data_free: 0
Auto_increment: NULL
Create_time: 2013-09-12 00:39:29
Update_time: 2013-09-12 00:39:29
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.00 sec)
2,auto_increment
當使用這個引數的時候,這個列一定要是主鍵
mysql> create table tt (id int auto_increment primary key , name varchar(30) , msg varchar(100)) engine = MyISAM;
Query OK, 0 rows affected (0.01 sec)
mysql> insert into tt(name,msg) values('chenzhongyang','good');
Query OK, 1 row affected (0.00 sec)
雖然我們沒有指定名字是chenzhongyang的id是1,但是有了auto_increment這個引數,系統會自動給他加上1
mysql> select * from tt;
+----+---------------+------+
| id | name | msg |
+----+---------------+------+
| 1 | chenzhongyang | good |
+----+---------------+------+
1 row in set (0.01 sec)
我們還可以設定auto_increment的值,但是這個值設定了的話,就會從這個值開始累積
mysql> alter table tt auto_increment=2000;
Query OK, 1 row affected (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> insert into tt(name,msg) values('tianhongyan','baby');
Query OK, 1 row affected (0.00 sec)
mysql> select * from tt;
+------+---------------+------+
| id | name | msg |
+------+---------------+------+
| 1 | chenzhongyang | good |
| 2000 | tianhongyan | baby |
+------+---------------+------+
2 rows in set (0.00 sec)
mysql> insert into tt(name,msg) values('zhongguo','XXXXXXX-YYYYYYYYY-+VVVV');
Query OK, 1 row affected (0.00 sec)
mysql> select * FROM tt;
+------+---------------+-------------------------+
| id | name | msg |
+------+---------------+-------------------------+
| 1 | chenzhongyang | good |
| 2000 | tianhongyan | baby |
| 2001 | zhongguo | XXXXXXX-YYYYYYYYY-+VVVV |
+------+---------------+-------------------------+
3 rows in set (0.00 sec)
還有一個函式比較有用last_insert_id()。這個函式可以查出最後一次insert的id
mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 2001 |
+------------------+
1 row in set (0.00 sec)
3,儲存結構
資料檔案(.MYD),索引檔案(.MYI)和結構檔案(.frm)
特點:可以在不同伺服器上複製資料檔案和索引檔案。
如果我們把索引檔案和資料檔案放到不同的機器上,那麼可以提高系統i/o
4,不支援事務
即使我們關閉autocommit,myisam引擎還是會立即執行我們的命令,這個時候rollback已經沒有用了
mysql> show variables like "%autocommit%";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set (0.00 sec)
mysql> set autocommit=OFF ;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like "%autocommit%";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | OFF |
+---------------+-------+
1 row in set (0.00 sec)
mysql> delete from tt where id=1;
Query OK, 1 row affected (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> select * from tt;
+------+-------------+-------------------------+
| id | name | msg |
+------+-------------+-------------------------+
| 2000 | tianhongyan | baby |
| 2001 | zhongguo | XXXXXXX-YYYYYYYYY-+VVVV |
+------+-------------+-------------------------+
2 rows in set (0.00 sec)
5,myisam_data_pointer_size
預設的指標大小是6byte,一個位元組是8bit那麼資料檔案的大小就是2的6*8次方byte
也就是1024*1024*1024*1024*256/1024/1024/1024/1024=256TB
mysql> show variables like "%pointer%";
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| myisam_data_pointer_size | 6 |
+--------------------------+-------+
1 row in set (0.00 sec)
我們來做個實驗試試
如果myisam_data_pointer_size=2,那麼就意味著一個表的最大資料檔案是65535/1024=64K
mysql> set global myisam_data_pointer_size=2;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like "%pointer%";
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| myisam_data_pointer_size | 2 |
+--------------------------+-------+
1 row in set (0.00 sec)
我們來建立一個 大表ss
mysql> create table ss select * from information_schema.tables ;
Query OK, 54 rows affected (0.09 sec)
Records: 54 Duplicates: 0 Warnings: 0
mysql> insert into ss select * from ss;
Query OK, 108 rows affected (0.01 sec)
Records: 108 Duplicates: 0 Warnings: 0
mysql> insert into ss select * from ss;
Query OK, 216 rows affected (0.01 sec)
Records: 216 Duplicates: 0 Warnings: 0
這個時候出現了表ss滿了的錯誤,我們看看資料檔案 是64K,要想繼續可以插入資料,那麼就要把這個引數調大
mysql> insert into ss select * from ss;
ERROR 1114 (HY000): The table 'ss' is full
mysql> insert into ss select * from ss;
ERROR 1114 (HY000): The table 'ss' is full
mysql> insert into ss select * from ss;
ERROR 1114 (HY000): The table 'ss' is full
[root@test3 test]# ls -lh
total 116K
-rw-rw----. 1 mysql mysql 9.3K Sep 12 06:44 ss.frm
-rw-rw----. 1 mysql mysql 64K Sep 12 06:44 ss.MYD
-rw-rw----. 1 mysql mysql 1.0K Sep 12 06:44 ss.MYI
mysql> insert into ss select * from ss;
ERROR 1114 (HY000): The table 'ss' is full
mysql> alter table ss max_ROWS=10000000000 ;
Query OK, 496 rows affected (0.11 sec)
Records: 496 Duplicates: 0 Warnings: 0
mysql> insert into ss select * from ss;
Query OK, 496 rows affected (0.02 sec)
Records: 496 Duplicates: 0 Warnings: 0
6,myisam的儲存行格式
MyISAM支援三種不同儲存格式。
其中兩個(固定格式和動態格式)根據正使用的列的型別來自動選擇。第三個,即已壓縮格式,只能使用myisampack工具來建立。
1.fixed靜態格式(固定長度)表的一般特徵:
·CHAR列對列寬度是空間填補的。
·非常快。
·容易快取。
·崩潰後容易重建,因為記錄位於固定位置。
·重新組織是不必要的,除非你刪除巨量的記錄並且希望為作業系統騰出磁碟空間。為此,可使用OPTIMIZETABLE或者myisamchk-r。
·通常比動態格式表需要更多的磁碟空間。
2.dynamic動態格式表的一般特徵:
·除了長度少於4的列外,所有的字串列是動態的。
·在每個記錄前面是一個點陣圖,該點陣圖表明哪一列包含空字串(對於字串列)或者0(對於數字列)。注意,這並不包括包含NULL值的列。如果一個字元列在拖曳空間移除後長度為零,或者一個數字列為零值,這都在點陣圖中標註了且列不被儲存到磁碟。非空字串被存為一個長度位元組加字串的內容。
·通常比固定長度表需要更少的磁碟空間。
·每個記錄僅使用必需大小的空間。儘管如此,如果一個記錄變大,它就按需要被分開成多片,造成記錄碎片的後果。比如,你用擴充套件行長度的資訊更新一行,該行就變得有碎片。在這種情況下,你可以時不時執行OPTIMIZETABLE或myisamchk-r來改善效能。可使用myisamchk-ei來獲取表的統計資料。
·動態格式表在崩潰後要比靜態格式表更難重建,因為一個記錄可能被分為多個碎片且連結(碎片)可能被丟失。
3.已壓縮表有下列特徵:
·已壓縮表佔據非常小的磁碟空間。這最小化了磁碟用量,當使用緩慢的磁碟(如CD-ROM)之時,這是很有用的。
·每個記錄是被單獨壓縮的,所以只有非常小的訪問開支。依據表中最大的記錄,一個記錄的頭在每個表中佔據1到3個位元組。每個列被不同地壓縮。通常每個列有一個不同的Huffman樹。一些壓縮型別如下:
-字尾空間壓縮。
-字首空間壓縮。
-零值的數用一個位來儲存。
-如果在一個整型列中的值有一個小的範圍,列被用最小可能的型別來儲存。比如,一個BIGINT列(8位元組),如果所有它的值在-128到127範圍內,它可以被儲存為TINYINT列(1位元組)
-如果一個列僅有一小組可能的值,列的型別被轉化成ENUM。
-一個列可以使用先前壓縮型別的任意合併。
·可以處理固定長度或動態長度記錄。
7,加鎖和併發
MyISAM儲存引擎只支援表鎖,這也是MySQL開始幾個版本中唯一支援的鎖型別。隨著應用對事務完整性和併發性要求的不斷提高,MySQL才開始開發基於事務的儲存引擎,後來慢慢出現了支援頁鎖的BDB儲存引擎和支援行鎖的InnoDB儲存引擎(實際InnoDB是單獨的一個公司,現在已經被Oracle公司收購)。但是MyISAM的表鎖依然是使用最為廣泛的鎖型別
加鎖:對整張表進行加鎖,而不是行。
併發:在讀資料的時候,所有的表上都可以獲得共享鎖(讀鎖),每個連線都不互相干擾。
在寫資料的時候,獲得排他鎖,會把整個表進行加鎖,而其他的連線請求(讀,寫請求)都處於等待中。
可以透過檢查table_locks_waited和table_locks_immediate狀態變數來分析系統上的表鎖定爭奪:
mysql> show status like 'table%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Table_locks_immediate | 2979 |
| Table_locks_waited | 0 |
+-----------------------+-------+
2 rows in set (0.00 sec))
如果Table_locks_waited的值比較高,則說明存在著較嚴重的表級鎖爭用情況。
對MyISAM表的讀操作,不會阻塞其他使用者對同一表的讀請求,但會阻塞對同一表的寫請求;對MyISAM表的寫操作,則會阻塞其他使用者對同一表的讀和寫操作;MyISAM表的讀操作與寫操作之間,以及寫操作之間是序列的
MyISAM在執行查詢語句(SELECT)前,會自動給涉及的所有表加讀鎖,在執行更新操作(UPDATE、DELETE、INSERT等)前,會自動給涉及的表加寫鎖,這個過程並不需要使用者干預,因此,使用者一般不需要直接用LOCKTABLE命令給MyISAM表顯式加鎖。顯式加鎖基本上都是為了方便而已,並非必須如此。也正是因為這樣,所以myisam不會產生死鎖。
READ鎖表
獲得表film_text的READ鎖定
mysql> lock table film_text read;
Query OK, 0 rows affected (0.00 sec)
當前session可以查詢該表記錄
mysql> select film_id,title from film_text where film_id = 1001;
+---------+------------------+
| film_id | title |
+---------+------------------+
| 1001 | ACADEMY DINOSAUR |
+---------+------------------+
1 row in set (0.00 sec)
其他session也可以查詢該表的記錄
mysql> select film_id,title from film_text where film_id = 1001;
+---------+------------------+
| film_id | title |
+---------+------------------+
| 1001 | ACADEMY DINOSAUR |
+---------+------------------+
1 row in set (0.00 sec)
當前session不能查詢沒有鎖定的表
mysql> select film_id,title from film where film_id = 1001;
ERROR 1100 (HY000): Table 'film' was not locked with LOCK TABLES
其他session可以查詢或者更新未鎖定的表
mysql> select film_id,title from film where film_id = 1001;
+---------+---------------+
| film_id | title |
+---------+---------------+
| 1001 | update record |
+---------+---------------+
1 row in set (0.00 sec)
mysql> update film set title = 'Test' where film_id = 1001;
Query OK, 1 row affected (0.04 sec)
Rows matched: 1 Changed: 1 Warnings: 0
當前session中插入或者更新鎖定的表都會提示錯誤:
mysql> insert into film_text (film_id,title) values(1002,'Test');
ERROR 1099 (HY000): Table 'film_text' was locked with a READ lock and can't be updated
mysql> update film_text set title = 'Test' where film_id = 1001;
ERROR 1099 (HY000): Table 'film_text' was locked with a READ lock and can't be updated
其他session更新鎖定表會等待獲得鎖:
mysql> update film_text set title = 'Test' where film_id = 1001;
等待
釋放鎖
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
等待
Session獲得鎖,更新操作完成:
mysql> update film_text set title = 'Test' where film_id = 1001;
Query OK, 1 row affected (1 min 0.71 sec)
Rows matched: 1 Changed: 1 Warnings: 0
當使用LOCK TABLES時,不僅需要一次鎖定用到的所有表,而且,同一個表在SQL語句中出現多少次,就要透過與SQL語句中相同的別名鎖定多少次,否則也會出錯!舉例說明如下。
(1)對actor表獲得讀鎖:
mysql> lock table actor read;
Query OK, 0 rows affected (0.00 sec)
(2)但是透過別名訪問會提示錯誤:
mysql> select a.first_name,a.last_name,b.first_name,b.last_name from actor a,actor b where a.first_name = b.first_name and a.first_name = 'Lisa' and a.last_name = 'Tom' and a.last_name <> b.last_name;
ERROR 1100 (HY000): Table 'a' was not locked with LOCK TABLES
(3)需要對別名分別鎖定:
mysql> lock table actor as a read,actor as b read;
Query OK, 0 rows affected (0.00 sec)
(4)按照別名的查詢可以正確執行:
mysql> select a.first_name,a.last_name,b.first_name,b.last_name from actor a,actor b where a.first_name = b.first_name and a.first_name = 'Lisa' and a.last_name = 'Tom' and a.last_name <> b.last_name;
+------------+-----------+------------+-----------+
| first_name | last_name | first_name | last_name |
+------------+-----------+------------+-----------+
| Lisa | Tom | LISA | MONROE |
+------------+-----------+------------+-----------+
1 row in set (0.00 sec)
WRITE鎖表
獲得表film_text的WRITE鎖定
mysql> lock table film_text write;
Query OK, 0 rows affected (0.00 sec)
當前session對鎖定表的查詢、更新、插入操作都可以執行:
mysql> select film_id,title from film_text where film_id = 1001;
+---------+-------------+
| film_id | title |
+---------+-------------+
| 1001 | Update Test |
+---------+-------------+
1 row in set (0.00 sec)
mysql> insert into film_text (film_id,title) values(1003,'Test');
Query OK, 1 row affected (0.00 sec)
mysql> update film_text set title = 'Test' where film_id = 1001;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
其他session對鎖定表的查詢被阻塞,需要等待鎖被釋放:
mysql> select film_id,title from film_text where film_id = 1001;
等待
釋放鎖:
併發插入(ConcurrentInserts)
上文提到過MyISAM表的讀和寫是序列的,但這是就總體而言的。在一定條件下,MyISAM表也支援查詢和插入操作的併發進行。
MyISAM儲存引擎有一個系統變數concurrent_insert,專門用以控制其併發插入的行為,其值分別可以為0、1或2。
l當concurrent_insert設定為0時,不允許併發插入。
l當concurrent_insert設定為1時,如果MyISAM表中沒有空洞(即表的中間沒有被刪除的行),MyISAM允許在一個程式讀表的同時,另一個程式從表尾插入記錄。這也是MySQL的預設設定。
l當concurrent_insert設定為2時,無論MyISAM表中有沒有空洞,都允許在表尾併發插入記錄。
在如表20-4所示的例子中,session_1獲得了一個表的READLOCAL鎖,該執行緒可以對錶進行查詢操作,但不能對錶進行更新操作;其他的執行緒(session_2),雖然不能對錶進行刪除和更新操作,但卻可以對該表進行併發插入操作,這裡假設該表中間不存在空洞。
表20-4MyISAM儲存引擎的讀寫(INSERT)併發例子
session_1
session_2
獲得表film_text的READ LOCAL鎖定
mysql> lock table film_text read local;
Query OK, 0 rows affected (0.00 sec)
當前session不能對鎖定表進行更新或者插入操作:
mysql> insert into film_text (film_id,title) values(1002,'Test');
ERROR 1099 (HY000): Table 'film_text' was locked with a READ lock and can't be updated
mysql> update film_text set title = 'Test' where film_id = 1001;
ERROR 1099 (HY000): Table 'film_text' was locked with a READ lock and can't be updated
其他session可以進行插入操作,但是更新會等待:
mysql> insert into film_text (film_id,title) values(1002,'Test');
Query OK, 1 row affected (0.00 sec)
mysql> update film_text set title = 'Update Test' where film_id = 1001;
等待
當前session不能訪問其他session插入的記錄:
mysql> select film_id,title from film_text where film_id = 1002;
Empty set (0.00 sec)
釋放鎖:
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
等待
當前session解鎖後可以獲得其他session插入的記錄:
mysql> select film_id,title from film_text where film_id = 1002;
+---------+-------+
| film_id | title |
+---------+-------+
| 1002 | Test |
+---------+-------+
1 row in set (0.00 sec)
Session2獲得鎖,更新操作完成:
mysql> update film_text set title = 'Update Test' where film_id = 1001;
Query OK, 1 row affected (1 min 17.75 sec)
Rows matched: 1 Changed: 1 Warnings: 0
可以利用MyISAM儲存引擎的併發插入特性,來解決應用中對同一表查詢和插入的鎖爭用。例如,將concurrent_insert系統變數設為2,總是允許併發插入;同時,透過定期在系統空閒時段執行OPTIMIZETABLE語句來整理空間碎片,收回因刪除記錄而產生的中間空洞
MyISAM的鎖排程
MyISAM儲存引擎的讀鎖和寫鎖是互斥的,讀寫操作是序列的。那麼,一個程式請求某個MyISAM表的讀鎖,同時另一個程式也請求同一表的寫鎖,MySQL如何處理呢?答案是寫程式先獲得鎖。不僅如此,即使讀請求先到鎖等待佇列,寫請求後到,寫鎖也會插到讀鎖請求之前!這是因為MySQL認為寫請求一般比讀請求要重要。這也正是MyISAM表不太適合於有大量更新操作和查詢操作應用的原因,因為,大量的更新操作會造成查詢操作很難獲得讀鎖,從而可能永遠阻塞。這種情況有時可能會變得非常糟糕!幸好我們可以透過一些設定來調節MyISAM的排程行為。
透過指定啟動引數low-priority-updates,使MyISAM引擎預設給予讀請求以優先的權利。
透過執行命令SETLOW_PRIORITY_UPDATES=1,使該連線發出的更新請求優先順序降低。
透過指定INSERT、UPDATE、DELETE語句的LOW_PRIORITY屬性,降低該語句的優先順序。
雖然上面3種方法都是要麼更新優先,要麼查詢優先的方法,但還是可以用其來解決查詢相對重要的應用(如使用者登入系統)中,讀鎖等待嚴重的問題。
另外,MySQL也提供了一種折中的辦法來調節讀寫衝突,即給系統引數max_write_lock_count設定一個合適的值,當一個表的讀鎖達到這個值後,MySQL就暫時將寫請求的優先順序降低,給讀程式一定獲得鎖的機會。
上面已經討論了寫優先排程機制帶來的問題和解決辦法。這裡還要強調一點:一些需要長時間執行的查詢操作,也會使寫程式“餓死”!因此,應用中應儘量避免出現長時間執行的查詢操作,不要總想用一條SELECT語句來解決問題,因為這種看似巧妙的SQL語句,往往比較複雜,執行時間較長,在可能的情況下可以透過使用中間表等措施對SQL語句做一定的“分解”,使每一步查詢都能在較短時間完成,從而減少鎖衝突。如果複雜查詢不可避免,應儘量安排在資料庫空閒時段執行,比如一些定期統計可以安排在夜間執行。
©著作權歸作者所有:來自51CTO部落格作者陳仲陽0的原創作品,如需轉載,請註明出處,否則將追究法律責任
mysql資料庫
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/758/viewspace-2820719/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MySQL儲存引擎--MyISAM與InnoDB區別MySql儲存引擎
- MySQL儲存引擎:MyISAM和InnoDB的區別MySql儲存引擎
- 總結MySQL儲存引擎MyISAM與InnoDB區別MySql儲存引擎
- 十八、Mysql儲存引擎並不只有MyISAM、InnoDB——精髓MySql儲存引擎
- MySQL三種InnoDB、MyISAM和MEMORY儲存引擎對比MySql儲存引擎
- MySQL儲存引擎簡介及MyISAM和InnoDB的區別MySql儲存引擎
- MySQL兩種儲存引擎: MyISAM和InnoDB 簡單總結MySql儲存引擎
- MySQL儲存引擎MySql儲存引擎
- MySQL 儲存引擎MySql儲存引擎
- 重新學習Mysql資料庫3:Mysql儲存引擎與資料儲存原理MySql資料庫儲存引擎
- (MariaDB/MySQL)MyISAM儲存引擎讀、寫操作的優先順序MySql儲存引擎
- mysql學習6:第三章MYSQL 體系結構與儲存引擎MySql儲存引擎
- MySQL InnoDB儲存引擎MySql儲存引擎
- MySQL系列-儲存引擎MySql儲存引擎
- 服務端指南 資料儲存篇 | MySQL(02) 儲存引擎的 InnoDB 與 MyISAM 之爭服務端MySql儲存引擎
- MySQL InnoDB儲存引擎體系結構MySql儲存引擎
- MySQL體系結構與儲存引擎MySql儲存引擎
- mysql常用儲存引擎(InnoDB、MyISAM、MEMORY、MERGE、ARCHIVE)介紹與如何選擇MySql儲存引擎Hive
- MySQL常見的兩種儲存引擎:MyISAM與InnoDB的愛恨情仇MySql儲存引擎
- MySQL之儲存引擎InnoDB和MyISAM的區別及底層詳解MySql儲存引擎
- MySQL-05.儲存引擎MySql儲存引擎
- MySQL入門--儲存引擎MySql儲存引擎
- 理解mysql的儲存引擎MySql儲存引擎
- MySQL之四 儲存引擎MySql儲存引擎
- 【MySQL】MySQL(四)儲存引擎、索引、鎖、叢集MySql儲存引擎索引
- MySQL federated儲存引擎測試MySql儲存引擎
- 2_mysql(索引、儲存引擎)MySql索引儲存引擎
- MySQL InnoDB 儲存引擎探祕MySql儲存引擎
- 說說自己對於 MySQL 常見的兩種儲存引擎:MyISAM與 InnoDB的理解MySql儲存引擎
- 簡單認識MySQL儲存引擎MySql儲存引擎
- MySQL索引、事務與儲存引擎MySql索引儲存引擎
- 聊一聊MySQL的儲存引擎MySql儲存引擎
- MySQL儲存引擎入門介紹MySql儲存引擎
- MySQL資料庫操作、儲存引擎MySql資料庫儲存引擎
- 如何選擇mysql的儲存引擎MySql儲存引擎
- 小談mysql儲存引擎優化MySql儲存引擎優化
- Mysql 5.7儲存過程的學習MySql儲存過程
- MyISAM與innoDB儲存引擎有何差別儲存引擎