mysql 设置 file_prev_改进MySQL的table_cache_MySQL - prev

58e8d81c4a0d115f2a9f9f245fa77d87.png

prev() 函数被用来匹配元素集的前一个兄弟元素,仅仅只有前一个兄弟元素被选择,其子元素将被忽略。 prev() 函数可以允许通过选择器来过滤,例如 prev(‘p’) 被用来选择匹配元素的前一个元素是兄弟元素的p元素。

bitsCN.com

以下为本人在工作中的碎碎念,记录的比较凌乱……

........................................................................

在mysql里面有一个参数table_cache,当设置过大时,会产生明显的效率下降。这是因为扫描open_cache哈希表时,使用的线性扫描,时间复杂度为O(n),mysql的bug list上有人提供了一个patch(http://bugs.mysql.com/bug.php?id=33948),可以把时间降到o(1),其基本思想是为table实例增加三个指针,来维护一个空闲链表。

首先,我们分析一下mysql在打开一个表时如何工作:

在mysql里,table_cache是一个比较重要的参数。由于多线程机制,每个线程独自打开自己需要的标的文件描述符,而不是共享已经打开的。

1. table_cache key (见create_table_def_key)

在内存里,table cache使用hash表来存储,key为 database_name/0table_name/0+(可选的,用于临时表)

这里对于临时表会做特殊处理,需要增加额外的信息来保证临时表在slave端是唯一的

增加8个字节:前4个字节为master thread id,后4个字节为slavb

2.打开表时候的处理:open_table

***************

必要的检查:线程栈是否足够,thd是否被kill

**************

全局锁:lock_open

*************************

首先判断是否是临时表

*************************

这里有一段很有意思的逻辑,当需要打开表时,总是先从临时表链表中查找表。也就是说,当存在一个与实际表同名的临时表时,会总是操作临时表

if (!table_list->skip_temporary)

{

for (table= thd->temporary_tables; table ; table=table->next)

{

**********************************************

非临时表,且处于pre-locked 或lock_tables mode(thd->locked_tables || thd->prelocked_mode)

即该线程已经打开或锁定了一些表,从thd->open_tables里查询,当不存在时,返回error

**********************************************

if (thd->locked_tables || thd->prelocked_mode)

{ // Using table locks

TABLE *best_table= 0;

int best_distance= INT_MIN;

for (table=thd->open_tables; table ; table=table->next)

{

*******************************************************

正常情况:

1. 首先尝试从table cache中取table

2. 当找到的TABLE实例是nam-locked的,或者一些线程正在flush tables,我们需要等待,直到锁释放

3. 如果不存在这样的TABLE,我们需要创建TABLE,并将其加入到cache中

!这些操作都需要全局锁:LOCK_open,来保护table cache和磁盘上的表定义

*******************************************************

如果这是该query打开的第一个表:设置thd->version = refresh_version,这样,当我们打开剩余表的过程中,如果version发生了变化,则需要back off,关闭所有已经打开的并重新打开表

目前refresh_version只会被FLUSH TABLES命令改变

if (thd->handler_tables)

mysql_ha_flush(thd); //刷新(关闭并标记为re-open)所有需要reopen的表

查询table cache的过程:

for (table= (TABLE*) hash_first(&open_cache, (uchar*) key, key_length, //基于同一个key来查找hash表

&state);

table && table->in_use ;

table= (TABLE*) hash_next(&open_cache, (uchar*) key, key_length,

&state))

{

**********************************

flush tables marked for flush.

Normally, table->s->version contains the value of

refresh_version from the moment when this table was

(re-)opened and added to the cache.

If since then we did (or just started) FLUSH TABLES

statement, refresh_version has been increased.

For "name-locked" TABLE instances, table->s->version is set

to 0 (see lock_table_name for details).

In case there is a pending FLUSH TABLES or a name lock, we

need to back off and re-start opening tables.

If we do not back off now, we may dead lock in case of lock

order mismatch with some other thread:

c1: name lock t1; -- sort of exclusive lock

c2: open t2; -- sort of shared lock

c1: name lock t2; -- blocks

c2: open t1; -- blocks

*********************************

if (table->needs_reopen_or_name_lock()) //Is this instance of the table should be reopen or represents a name-lock?

{}

}

if (table)

************

从unused_tables链表中移除刚找到的table

************

else

***********

创建一个新的table实例,并插入到open cache中

***********

while (open_cache.records > table_cache_size && unused_tables) //当cache满时,从中释放未使用的TABLE实例

hash_delete(&open_cache,(uchar*) unused_tables);

if (table_list->create) //创建一个新表

{

*******

检查表是否存在:check_if_table_exists

*******

在table cache的hash中创建一个placeholder(占位符):table_cache_insert_placeholder

将占位符链到open tables list上:

table->open_placeholder= 1;

table->next= thd->open_tables;

thd->open_tables= table;

return table

}

创建一个新的table实例

分配内存table=(TABLE*) my_malloc(sizeof(*table),MYF(MY_WME))

error= open_unireg_entry(thd, table, table_list, alias, key, key_length,

mem_root, (flags & OPEN_VIEW_NO_PARSE));

如果是视图or error < 0 释放内存,返回;

my_hash_insert(&open_cache,(uchar*) table)

------------------------------------------------

patch:http://bugs.mysql.com/bug.php?id=33948

增加3个指针:

hash_head:

hash_prev: always point to unused table cached items

hash_next: always point to used table cached items

修改的函数:

free_cache_entry //释放一个表的内存。

close_thread_table //move one table to free list

reopen_name_locked_table //重新打开表,保持链表结构

table_cache_insert_placeholder

open_table

------------------------------------------------------------------------

总结:

增加了三个指针:

hash_head:

hash_prev:

hash_next:

!.............................!head!.........................!

head的左边为空闲item链表

head的右边为占用的item链表

所有item通过hash_prev和hash_next进行双向指针

右边的item的hash_head指向head

操作链表:

1)插入新空闲item:在head节点前加入

2)插入新的被占用item:在head后面加入

3)从链表中删除item:

---若该item为head,修改head右侧的item的hash_head指向head->next

---否则,直接删除item,并释放内存。。

查询空闲节点:

1) 找到head

2) 检测head是否in_use,为False则table = head, true则找到table = head->prev

3)当table 不为NULL时,表示找到一个item,将其插入到head右侧

3) table依旧为NULL---->创建新item,将其插入到head右侧

------------------------------

转载请注明:印风bitsCN.com

prev() 函数被用来匹配元素集的前一个兄弟元素,仅仅只有前一个兄弟元素被选择,其子元素将被忽略。 prev() 函数可以允许通过选择器来过滤,例如 prev(‘p’) 被用来选择匹配元素的前一个元素是兄弟元素的p元素。

这次给大家带来jQuery的prev()使用详解,jQuery的prev()使用注意事项有哪些,下面就是实战案例,一起来看一下。prev() 函数被用来匹配元素集的前一个兄弟元素,仅仅只有前一个兄弟元素被选择,其子元素将...

PHP prev()函数用于将数组的内部指针倒回一位。php prev()函数 语法作用:将内部指针指向数组中的上一个元素,并输出。语法:prev(array)参数:array必需。指定需要操作的数组...

...节点寻找到所要删除节点的上一个节点(prevNode)将prevNode中的指针指向NULL在列表中间删除某个节点寻找到所要删除节点的上一个节点(prevNode)将prevNode中的指...

...

{ subject: 'english', score: 80 }

];

const sum = result.reduce((prev, cur) => prev + cur.score, 0);

const sum = result.reduce((prev,

...中计划功能的说明。其中大部分功能在Visual Studio “15” Preview 4中能运行。现在是最好的试用时期,请记录下你们的想法。

C#7.0语言增加了许多的新功能,促使专注于数据消费,简化代码和性能。

或许最大的特征是...

...中计划功能的说明。其中大部分功能在Visual Studio “15” Preview 4中能运行。现在是最好的试用时期,请记录下你们的想法。

C#7.0语言增加了许多的新功能,促使专注于数据消费,简化代码和性能。

或许最大的特征是...

...e.LinkedListNode = function () { this.data = null;//数据域 this.prev = null;//前驱 this.next = null;//后驱 }; Dare.extend(Dare.LinkedListNode, Dare); Dare

...n(element) {

this.element = element;

this.next = null;

this.prev = null;

};

var length = 0,

head = null,

tail = nu

本文主要介绍了jQuery里prev()的简单操作代码,非常不错,具有参考借鉴价值,需要的朋友可以参考下,希望能帮助到大家。prev() 函数被用来匹配元素集的前一个兄弟元素,仅仅只有前一个兄弟元素被选择,其子元素将被...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值