设为首页 收藏本站
查看: 759|回复: 0

[经验分享] mysql dba系统学习(20)mysql存储引擎MyISAM

[复制链接]

尚未签到

发表于 2018-9-27 14:00:11 | 显示全部楼层 |阅读模式
  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;
  
+----+---------------+------+
  
|>  
+----+---------------+------+
  
|  1 | chenzhongyang | good |
  
+----+---------------+------+
  
1 row in set (0.01 sec)
  我们还可以设置auto_increment的值,但是这个值设置了的话,就会从这个值开始累积
mysql>>
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;
  
+------+---------------+------+

  
|>  
+------+---------------+------+
  
|    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;
  
+------+---------------+-------------------------+

  
|>  
+------+---------------+-------------------------+
  
|    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>  
Query OK, 1 row affected (0.00 sec)
  
mysql> rollback;
  
Query OK, 0 rows affected, 1 warning (0.00 sec)
  
mysql> select   * from tt;
  
+------+-------------+-------------------------+

  
|>  
+------+-------------+-------------------------+
  
| 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>>  
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 |>  
+---------+------------------+
  
| 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 |>  
+---------+------------------+
  
| 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 |>  
+---------+---------------+
  
| 1001    | update record |
  
+---------+---------------+
  
1 row in set (0.00 sec)

  
mysql> update film set>  
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>  
ERROR 1099 (HY000): Table 'film_text' was locked with a READ lock and can't be updated
  
其他session更新锁定表会等待获得锁:

  
mysql> update film_text set>  
等待
  
释放锁
  
mysql> unlock tables;
  
Query OK, 0 rows affected (0.00 sec)
  
等待
  
Session获得锁,更新操作完成:

  
mysql> update film_text set>  
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 |>  
+---------+-------------+
  
| 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>  
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>  
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>  
等待
  
当前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 |>  
+---------+-------+
  
| 1002 | Test |
  
+---------+-------+
  
1 row in set (0.00 sec)
  
Session2获得锁,更新操作完成:

  
mysql> update film_text set>  
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语句做一定的“分解”,使每一步查询都能在较短时间完成,从而减少锁冲突。如果复杂查询不可避免,应尽量安排在数据库空闲时段执行,比如一些定期统计可以安排在夜间执行。



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-602892-1-1.html 上篇帖子: MySQL HA by using Mysql-mmm 下篇帖子: MySQL SQL优化之‘%’
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表