表对象缓存就是将表的字典信息缓存到内存中,用来提高对表的访问效率。某个表被访问后,在服务器没有关闭且表定义没有被修改的条件下,访问这个表时,只需从内存中找到这个缓存的表对象即可,而不必再次从系统表中读取它的定义解析。也说明,在某个表需要更改表结构时,这个表不能被其它用户打开,否则会产生MDL(元数据锁),错误表现是:waiting for table metadata lock.

mysql的表对象缓存比较特别,因为是插件式多存储引擎的,这样它的表对象缓存也就出现了两层,类似于开发语言中的类和对象的关系。(有开发基础的同学可能会更好的理解类和对象)
拿mysql两种常见的存储引擎:myisam innodb举例
myisam表文件:.frm .MYD .MYI ;
innodb表文件: .frm .ibd ;
因为mysql不同种类的表都有.frm表结构文件,这也是表缓存第一层需要读取的文件。
第一层缓存,也是静态缓存或称为共享(share)缓存,这相当于给表定义了一个结构类:
表对象缓存是把表结构缓存到内存中,也就是.frm文件,这个不分引擎表,都是有的。
表对象缓存的存储形式是以hash键值对存放在table_define_chche内存中的。
第二层缓存,也称动态缓存,是对表使用过程中的实例化。
对于同一个静态表缓存,每一次实例化都相当于打开一张表,会将这些信息存放到open_tables_cache中。可以直接通过命令:show open tables where in_use>0;查看当前已经打开的表。当一个操作完成后,它所实例化的表就不需要了,此时系统不是将这个本地的实例直接释放,而是将其保存下来,为了下次某个用户再次访问这个表是不需要重新实例化,当然会调用ha_reset将这个实例状态恢复。这也是为什么show open tables 会有大量的in_use=0的表。这些表有实例化,但是没有被使用。

现在可以知道,mysql中表对象的缓存其实是两部分,一部分是share的缓存,也就是多个不同表的share的缓存;另一部分是每个share结构被实例化后的实例对象的缓存,mysql用来管理缓存空间大小的方法是通过计数实现的。默认情况下,系统中总的share个数不超过table_definition_cache个。总共打开的表个数不超过table_open_cache个。
优缺点:
1.share缓存在使用时才读到内存中,相对去reload形式的全字典缓存,效率会查一下,但节省内存空间。
2.share缓存、table缓存 是以记个数的方式来控制的,这样没法准确控制内存的使用量。可能存在缓存个数已达上限,但内存剩余量还很大,或内存已达上限但缓存个数却很少。
其实mysql的表对象缓存内容很多,设计到源码的东西就不太容易理解了。我也是捋了一层最上面的东西,方便理解。
抛砖引玉,写的不对的地方尽情pen pen ~~




