如何减轻MySQL数据库的工作压力
当使用MySQL数据库的网站访问量越来越大的时候,它的码授码下压力也会越来越大,那么如何给MySQL数据库减压呢?那就是权源权源优化! 单机MySQL的码授码下优化有三种方法。分别是权源权源:一、服务器物理硬件的码授码下取线程句柄源码优化;二、MySQL安装时的权源权源编译优化;三、自身配置文件my.cnf的码授码下优化。一、权源权源服务器物理硬件的码授码下优化1、磁盘寻道能力(磁盘I/O) 是权源权源制约MySQL性能的最大因素之一,建议使用RAID1+0磁盘阵列,码授码下另外最好不要尝试使用RAID-5,权源权源因为MySQL在RAID-5磁盘阵列上的码授码下效率实际上并不是很快;2、CPU也很重要,权源权源对于MySQL应用,推荐使用DELL R,E @2.GHz(4 core)* 2或跟这个处理能力差不多的也行。 3、物理内存,物理内存对于一台使用MySQL的Database Server来说,服务器内存建议不要小于2GB,推荐使用4GB以上的物理内存。二、MySQL安装时的编译优化 建议采取编译安装的方法,这样性能上有较大提升,服务器系统建议用bit的Centos5.5,源码包的编译参数会默认以Debgu模式生成二进制代码,而Debug模式给MySQL带来的性能损失是比较大的,所以当我们编译准备安装的产品代码时,一定不要忘记使用“—without-debug”参数禁用Debug模式。 而如果把—with-mysqld-ldflags和—with-client-ldflags二个编译参数设置为—all-static的话,可以告诉编译器以静态方式编译和编译结果代码得到最高的性能。使用静态编译和使用动态编译的代码相比,性能差距可能会达到5%至%之多。三、自身配置文件my.cnf的优化 当解决了上述服务器硬件制约因素后,让我们看看MySQL自身的优化是如何操作的。对 MySQL自身的优化主要是对其配置文件my.cnf中的各项参数进行优化调整。下面我们介绍一些对性能影响较大的.net大作业源码参数。下面,我们根据以上硬件配置结合一份已经优化好的my.cnf进行说明:#vim /etc/my.cnf以下只列出my.cnf文件中[mysqld]段落中的内容,其他段落内容对MySQL运行性能影响甚微,因而姑且忽略。[mysqld] port = serverid = 1 socket = /tmp/mysql.sockskip-locking#避免MySQL的外部锁定,减少出错几率增强稳定性。skip-name-resolve#禁止MySQL对外部连接进行DNS解析,使用这一选项可以消除MySQL进行DNS解析的时间。但需要注意,如果开启该选项,则所有远程主机连接授权都要使用IP地址方式,否则MySQL将无法正常处理连接请求!back_log = #back_log参数的值指出在MySQL暂时停止响应新请求之前的短时间内多少个请求可以被存在堆栈中。 如果系统在一个短时间内有很多连接,则需要增大该参数的值,该参数值指定到来的TCP/IP连接的侦听队列的大小。不同的操作系统在这个队列大小上有它自 己的限制。 试图设定back_log高于你的操作系统的限制将是无效的。默认值为。对于Linux系统推荐设置为小于的整数。key_buffer_size = M#key_buffer_size指定用于索引的缓冲区大小,增加它可得到更好的索引处理性能。对于内存在4GB左右的服务器该参数可设置为M或M。注意:该参数值设置的过大反而会是服务器整体效率降低!max_allowed_packet = 4M thread_stack = K table_cache = K sort_buffer_size = 6M#查询排序时所能使用的缓冲区大小。注意:该参数对应的分配内存是每连接独占,如果有个连接,那么实际分配的总共排序缓冲区大小为 × 6 = MB。所以,对于内存在4GB左右的服务器推荐设置为6-8M。read_buffer_size = 4M#读查询操作所能使用的缓冲区大小。和sort_buffer_size一样,该参数对应的分配内存也是每连接独享。join_buffer_size = 8M#联合查询操作所能使用的缓冲区大小,和sort_buffer_size一样,该参数对应的分配内存也是每连接独享。myisam_sort_buffer_size = M table_cache = thread_cache_size = query_cache_size = M#指定MySQL查询缓冲区的大小。可以通过在MySQL控制台观察,如果Qcache_lowmem_prunes的值非常大,则表明经常出现缓冲不够 的情况;如果Qcache_hits的值非常大,则表明查询缓冲使用非常频繁,友情价源码网如果该值较小反而会影响效率,那么可以考虑不用查询缓冲;Qcache_free_blocks,如果该值非常大,则表明缓冲区中碎片很多。tmp_table_size = M max_connections = #指定MySQL允许的最大连接进程数。如果在访问论坛时经常出现Too Many Connections的错误提 示,则需要增大该参数值。max_connect_errors = wait_timeout = #指定一个请求的最大连接时间,对于4GB左右内存的服务器可以设置为5-。thread_concurrency = 8#该参数取值为服务器逻辑CPU数量*2,在本例中,服务器有2颗物理CPU,而每颗物理CPU又支持H.T超线程,所以实际取值为4*2=8;这个目前也是双四核主流服务器配置。skip-networking#开启该选项可以彻底关闭MySQL的TCP/IP连接方式,如果WEB服务器是以远程连接的方式访问MySQL数据库服务器则不要开启该选项!否则将无法正常连接!table_cache=#物理内存越大,设置就越大.默认为,调到-最佳innodb_additional_mem_pool_size=4M#默认为2Minnodb_flush_log_at_trx_commit=1#设置为0就是等到innodb_log_buffer_size列队满后再统一储存,默认为1innodb_log_buffer_size=2M#默认为1Minnodb_thread_concurrency=8#你的服务器CPU有几个就设置为几,建议用默认一般为8key_buffer_size=M#默认为,调到最佳tmp_table_size=M#默认为M,调到-最挂read_buffer_size=4M#默认为Kread_rnd_buffer_size=M#默认为Ksort_buffer_size=M#默认为Kthread_cache_size=#默认为query_cache_size=M 另外很多情况需要具体情况具体分析1、如果Key_reads太大,则应该把my.cnf中Key_buffer_size变大,保持Key_reads/Key_read_requests至少1/以上,越小越好。2、如果Qcache_lowmem_prunes很大,就要增加Query_cache_size的值。 通过参数设置进行性能优化或多或少可以带来性能的提升,但效果不一定会很突出。
MySQL 核心模块揭秘 | 期 | 回滚到 savepoint
深入理解 MySQL,了解如何实现部分回滚操作。本文由技术专家操盛春撰写,他在公众号『一树一溪』分享 MySQL 和 OceanBase 源码研究。本文基于 MySQL 8.0.,InnoDB 存储引擎,探讨核心模块的工作原理。
首先,我们创建测试表并插入数据。关键操作分为四个阶段,编号为 SQL 1 至 SQL 4,其中 SQL 4 是php影视分销源码讨论焦点。SQL 2 和 SQL 3 分别产生 undo 日志 0 和 1。
当执行事务时,产生的 binlog 日志在 trx cache 中。回滚整个事务时,需要清除这些日志。然而,实际操作中,binlog 回滚步骤看似简单,却并未执行真正清除,只是为后续的 InnoDB 回滚做准备。
InnoDB 回滚是关键环节,它会根据 undo 日志执行反向操作,恢复事务影响的数据。以 SQL 为例,会从最新的 undo 日志开始回滚,逐条执行反向操作,包括记录的删除。
回滚后,事务的执行状态需要通过提交事务来更新。这不同于 commit 语句,因为回滚操作已经改变了数据,即使从逻辑上看恢复了原样,也需要将 InnoDB 中的修改正式提交。
trx cache 中的 binlog 日志会在 InnoDB 回滚完成后进行清除,这个过程涉及内存 buffer 和磁盘临时文件。binlog 回滚步骤延迟到这个阶段,是因为在事务提交前,binlog 日志并不需要写入持久化存储。
总结起来,MySQL 的部分回滚包括:无实际动作的 binlog 回滚,执行 InnoDB 回滚恢复数据,然后提交 InnoDB 事务,最后清理 trx cache 中的临时 binlog。如果你对文中内容有疑问,欢迎留言交流。
对于 SQL 质量管理,如需更多工具支持,可以了解 SQLE,一个覆盖开发到生产环境的小米盒子3源码 SQL 管理平台,提供流程自动化和数据质量管理功能。
ä¼åmysql å¤å¤§å å centos6
ä¸ãmysqlçä¼åæè·¯
mysqlçä¼åå为两æ¹é¢ï¼
1. æå¡å¨ä½¿ç¨åçä¼å
2. æå¡ä½¿ç¨ä¸çä¼å
äºãmysqlçåºç¡ä¼åæ¥éª¤
1. 硬件级ä¼å
ï¼1ï¼. æ好mysqlèªå·±ä½¿ç¨ä¸å°ç©çæå¡å¨
ï¼2ï¼. å ååCPUæ¹é¢ï¼æ ¹æ®éæ±ç»äºmysqlæå¡å¨è¶³å¤å¤§çå åå足å¤å¤çCPUæ ¸æ°
(3). é¿å 使ç¨Swap交æ¢ååºâ交æ¢æ¶ä»ç¡¬ç读åçå®çé度å¾æ ¢ï¼æçDBAå®è£ ç³»ç»æ¶å°±ä¸è£ swapååº
ï¼4ï¼. å¦ææ¯mysql主åºï¼ç¡¬çå¯ä»¥éç¨æ¯è¾å¥½çé«é硬çï¼ç³»ç»ç¨SSDåºæ硬çï¼æ°æ®çç¨sasæ¿ä»£sata硬çï¼å°æä½ç³»ç»åæ°æ®ååºåå¼
ï¼5ï¼. mysql产ççæ¥å¿ä¸æ°æ®åºä¹æ¾å°ä¸åçç£çååºä¸é¢
ï¼6ï¼. mysqlæ°æ®åºç¡¬çæ ¼å¼åæ¶ï¼å¯ä»¥æå®æ´å°ç硬çå
ï¼7ï¼. å ³äºåRAIDæ¹é¢ï¼ä¸»åºå°½éåæRAIDï¼æ¢æé«äºæ°æ®ç读åé度ä¹æå°äºæ°æ®çå®å ¨æ§
ï¼8). æå¡å¨å线åçµï¼ä¿éæå¡å¨è¿è¡ç¨³å®ï¼ä¸ä¼å 为çªç¶æçµå½±åä¸å¡åæåç£çæ°æ®
2. mysqlæ°æ®åºè®¾è®¡ä¼å
ï¼1). æ ¹æ®éæ±éæ©æ£ç¡®çåå¨å¼æï¼æ¯å¦è¯´è¯»çç¹å«çå°±ç¨MySAM,å¦æ对äºå¡æ§è¦æ±é«å°±ç¨InnoDB
(2). 设置åççå段类ååå段é¿åº¦,æ¯å¦è¯´ä½ è¿ä¸ªå段就å¤ä¸ªåæ®µä½ è®¾ç½®æVARCHAR()å°±æ¯å¯¹ç£ç空é´ç浪费
ï¼3ï¼. é»è®¤å¼å°½å¯è½çä½¿ç¨ NOT NULLï¼å¦æ空å¼å¤ªå¤å¯¹mysqlçæ¥è¯¢ä¼æå½±åï¼å°¤å ¶æ¯å¨æ¥è¯¢è¯å¥ç¼åä¸é¢
ï¼4ï¼. å°½éå°ç使ç¨VARCHARï¼TEXTï¼BLOBè¿ä¸ä¸ªå段
ï¼5ï¼. æ·»å éå½ç´¢å¼(index) [åç§: æ®éç´¢å¼ã主é®ç´¢å¼ãå¯ä¸ç´¢å¼uniqueãå ¨æç´¢å¼]
ï¼6ï¼. ä¸è¦æ»¥ç¨ç´¢å¼ï¼å¤§è¡¨ç´¢å¼ï¼å°è¡¨ä¸ç´¢å¼
ï¼7ï¼. 表ç设计åçå(符å3NF)
3. mysqlé ç½®åæ°çä¼å
è¿éæ¯mysql5.5çæ¬çé ç½®æ件
vi my.cnf
[client]
port = #mysql客æ·ç«¯è¿æ¥æ¶çé»è®¤ç«¯å£
socket = /tmp/mysql.sock #ä¸mysqlæå¡å¨æ¬å°éä¿¡æ使ç¨çsocketæ件路å¾
default-character-set = utf8 #æå®é»è®¤å符é为utf8
[mysql]
no-auto-rehash #auto-rehashæ¯èªå¨è¡¥å ¨çææï¼å°±åæ们å¨linuxå½ä»¤è¡éè¾å ¥å½ä»¤çæ¶åï¼ä½¿ç¨tabé®çåè½æ¯ä¸æ ·çï¼è¿éæ¯é»è®¤çä¸èªå¨è¡¥å ¨
default-character-set = utf8 #æå®é»è®¤å符é为utf8
[mysqld]
user = mysql
port =
character-set-server = utf8 #设置æå¡å¨ç«¯çå符ç¼ç
socket = /tmp/mysql.sock
basedir = /application/mysql
datadir = /mysqldata
skip-locking #é¿å MySQLçå¤é¨éå®ï¼åå°åºéå çå¢å¼ºç¨³å®æ§ã
open_files_limit = #MySQLæå¼çæ件æ述符éå¶ï¼é»è®¤æå°;å½open_files_limit没æ被é ç½®çæ¶åï¼æ¯è¾max_connections*5åulimit -nçå¼ï¼åªä¸ªå¤§ç¨åªä¸ªï¼å½open_file_limit被é ç½®çæ¶åï¼æ¯è¾open_files_limitåmax_connections*5çå¼ï¼åªä¸ªå¤§ç¨åªä¸ªã
back_log = #back_logåæ°çå¼æåºå¨MySQLææ¶åæ¢ååºæ°è¯·æ±ä¹åççæ¶é´å å¤å°ä¸ªè¯·æ±å¯ 以被åå¨å æ ä¸ã å¦æç³»ç»å¨ä¸ä¸ªçæ¶é´å æå¾å¤è¿æ¥ï¼åéè¦å¢å¤§è¯¥åæ°çå¼ï¼è¯¥åæ°å¼æå®å°æ¥çTCP/IPè¿æ¥ç侦å¬éåç大å°ãä¸åçæä½ç³»ç»å¨è¿ä¸ªéå大å°ä¸æå®èª å·±çéå¶ã è¯å¾è®¾back_logé«äºä½ çæä½ç³»ç»çéå¶å°æ¯æ æçãé»è®¤å¼ä¸ºã对äºLinuxç³»ç»æ¨è设置为å°äºçæ´æ°ã
max_connections = #MySQLçæ大è¿æ¥æ°ï¼å¦ææå¡å¨ç并åè¿æ¥è¯·æ±éæ¯è¾å¤§ï¼å»ºè®®è°é«æ¤å¼ï¼ä»¥å¢å 并è¡è¿æ¥æ°éï¼å½ç¶è¿å»ºç«å¨æºå¨è½æ¯æçæ åµä¸ï¼å 为å¦æè¿æ¥æ°è¶å¤ï¼ ä»äºMySQLä¼ä¸ºæ¯ä¸ªè¿æ¥æä¾è¿æ¥ç¼å²åºï¼å°±ä¼å¼éè¶å¤çå åï¼æ以è¦éå½è°æ´è¯¥å¼ï¼ä¸è½ç²ç®æé«è®¾å¼ãå¯ä»¥è¿âconn%âéé 符æ¥çå½åç¶æçè¿æ¥ æ°éï¼ä»¥å®å¤ºè¯¥å¼ç大å°ã
max_connect_errors = #对äºåä¸ä¸»æºï¼å¦ææè¶ åºè¯¥åæ°å¼ä¸ªæ°çä¸æé误è¿æ¥ï¼å该主æºå°è¢«ç¦æ¢è¿æ¥ãå¦é对该主æºè¿è¡è§£ç¦ï¼æ§è¡ï¼FLUSH HOSTã
table_cache = #ç©çå åè¶å¤§,设置就è¶å¤§.é»è®¤ä¸º,è°å°-æä½³
external-locking = FALSE #使ç¨âskip-external-locking MySQLé项以é¿å å¤é¨éå®ã该é项é»è®¤å¼å¯
max_allowed_packet =8M #设置æ大å ,éå¶serveræ¥åçæ°æ®å 大å°ï¼é¿å è¶ é¿SQLçæ§è¡æé®é¢ é»è®¤å¼ä¸ºMï¼å½MySQL客æ·ç«¯æmysqldæå¡å¨æ¶å°å¤§äºmax_allowed_packetåèçä¿¡æ¯å æ¶ï¼å°ååºâä¿¡æ¯å è¿å¤§âé误ï¼å¹¶å ³éè¿æ¥ã对äºæäºå®¢æ·ç«¯ï¼å¦æéä¿¡ä¿¡æ¯å è¿å¤§ï¼å¨æ§è¡æ¥è¯¢æé´ï¼å¯è½ä¼éâ丢失ä¸MySQLæå¡å¨çè¿æ¥âé误ãé»è®¤å¼Mã
sort_buffer_size = 6M #ç¨äºè¡¨é´å ³èç¼åç大å°ï¼æ¥è¯¢æåºæ¶æè½ä½¿ç¨çç¼å²åºå¤§å°ã注æï¼è¯¥åæ°å¯¹åºçåé å åæ¯æ¯è¿æ¥ç¬å ï¼å¦ææ个è¿æ¥ï¼é£ä¹å®é åé çæ»å ±æåºç¼å²åºå¤§å°ä¸º à 6 ï¼ MBãæ以ï¼å¯¹äºå åå¨4GBå·¦å³çæå¡å¨æ¨è设置为6-8Mã
join_buffer_size = 6M #èåæ¥è¯¢æä½æè½ä½¿ç¨çç¼å²åºå¤§å°ï¼åsort_buffer_sizeä¸æ ·ï¼è¯¥åæ°å¯¹åºçåé å åä¹æ¯æ¯è¿æ¥ç¬äº«ã
thread_cache_size = #æå¡å¨çº¿ç¨ç¼åè¿ä¸ªå¼è¡¨ç¤ºå¯ä»¥éæ°å©ç¨ä¿åå¨ç¼åä¸çº¿ç¨çæ°é,å½æå¼è¿æ¥æ¶å¦æç¼åä¸è¿æ空é´,é£ä¹å®¢æ·ç«¯ç线ç¨å°è¢«æ¾å°ç¼åä¸,å¦æ线ç¨éæ°è¢«è¯·æ±ï¼ é£ä¹è¯·æ±å°ä»ç¼åä¸è¯»å,å¦æç¼åä¸æ¯ç©ºçæè æ¯æ°ç请æ±ï¼é£ä¹è¿ä¸ªçº¿ç¨å°è¢«éæ°å建,å¦ææå¾å¤æ°ç线ç¨ï¼å¢å è¿ä¸ªå¼å¯ä»¥æ¹åç³»ç»æ§è½.éè¿æ¯è¾ Connections å Threads_created ç¶æçåéï¼å¯ä»¥çå°è¿ä¸ªåéçä½ç¨
thread_concurrency = 8 #设置thread_concurrencyçå¼çæ£ç¡®ä¸å¦, 对mysqlçæ§è½å½±åå¾å¤§, å¨å¤ä¸ªcpu(æå¤æ ¸)çæ åµä¸ï¼é误设置äºthread_concurrencyçå¼, ä¼å¯¼è´mysqlä¸è½å åå©ç¨å¤cpu(æå¤æ ¸), åºç°åä¸æ¶å»åªè½ä¸ä¸ªcpu(ææ ¸)å¨å·¥ä½çæ åµãthread_concurrencyåºè®¾ä¸ºCPUæ ¸æ°ç2å. æ¯å¦æä¸ä¸ªåæ ¸çCPU, é£ä¹thread_concurrencyçåºè¯¥ä¸º4; 2个åæ ¸çcpu, thread_concurrencyçå¼åºä¸º8ï¼å±éç¹ä¼ååæ°
query_cache_size = 2M #æå®MySQLæ¥è¯¢ç¼å²åºç大å°ï¼å¨æ°æ®åºåå ¥éææ¯æ´æ°éä¹æ¯è¾å¤§çç³»ç»ï¼è¯¥åæ°ä¸éååé è¿å¤§ãèä¸å¨é«å¹¶åï¼åå ¥é大çç³»ç»ï¼å»ºç³»æ该åè½ç¦æã
query_cache_limit = 1M #é»è®¤æ¯4KBï¼è®¾ç½®å¼å¤§å¯¹å¤§æ°æ®æ¥è¯¢æ好å¤ï¼ä½å¦æä½ çæ¥è¯¢é½æ¯å°æ°æ®æ¥è¯¢ï¼å°±å®¹æé æå åç¢çå浪费
query_cache_min_res_unit = 2k #MySQLåæ°ä¸query_cache_min_res_unitæ¥è¯¢ç¼åä¸çåæ¯ä»¥è¿ä¸ªå¤§å°è¿è¡åé çï¼ä½¿ç¨ä¸é¢çå ¬å¼è®¡ç®æ¥è¯¢ç¼åçå¹³å大å°ï¼æ ¹æ®è®¡ç®ç»æ设置è¿ä¸ªåéï¼MySQLå°±ä¼æ´ææå°ä½¿ç¨æ¥è¯¢ç¼åï¼ç¼åæ´å¤çæ¥è¯¢ï¼åå°å åç浪费ã
default_table_type = InnoDB #é»è®¤è¡¨çå¼æ为InnoDB
thread_stack = K #éå®ç¨äºæ¯ä¸ªæ°æ®åºçº¿ç¨çæ 大å°ãé»è®¤è®¾ç½®è¶³ä»¥æ»¡è¶³å¤§å¤æ°åºç¨transaction_isolation = READ-COMMITTED #设å®é»è®¤çäºå¡é离级å«.å¯ç¨ç级å«å¦ä¸:
READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE,1.READ UNCOMMITTED-读æªæ交2.READ COMMITTE-读已æ交3.REPEATABLE READ -å¯éå¤è¯»4.SERIALIZABLE -串è¡
tmp_table_size = M #tmp_table_size çé»è®¤å¤§å°æ¯ Mãå¦æä¸å¼ 临æ¶è¡¨è¶ åºè¯¥å¤§å°ï¼MySQL产çä¸ä¸ª The table tbl_name is full å½¢å¼çé误ï¼å¦æä½ åå¾å¤é«çº§ GROUP BY æ¥è¯¢ï¼å¢å tmp_table_size å¼ã
max_heap_table_size = M #å å表ï¼å å表ä¸æ¯æäºå¡ï¼å å表使ç¨åå¸æ£åç´¢å¼ææ°æ®ä¿åå¨å åä¸ï¼å æ¤å ·ææå¿«çé度ï¼éåç¼åä¸å°åæ°æ®åºï¼ä½æ¯ä½¿ç¨ä¸åå°ä¸äºéå¶
long_query_time = 1 #è®°å½æ¶é´è¶ è¿1ç§çæ¥è¯¢è¯å¥
log_long_format #
log-error = /logs/error.log #å¼å¯mysqlé误æ¥å¿ï¼è¯¥é项æå®mysqldä¿åé误æ¥å¿æ件çä½ç½®
log-slow-queries = /logs/slow.log #æ ¢æ¥è¯¢æ¥å¿æ件路å¾
pid-file = /pids/mysql.pid
log-bin = /binlog/mysql-bin #binlogæ¥å¿ä½ç½®ä»¥åbinlogçå称
relay-log = /relaylog/relay-bin #relaylogæ¥å¿ä½ç½®ä»¥å称
binlog_cache_size = 1M #binlog_cache_size å°±æ¯æ»¡è¶³ä¸¤ç¹çï¼ä¸ä¸ªäºå¡ï¼å¨æ²¡ææ交ï¼uncommittedï¼çæ¶åï¼äº§ççæ¥å¿ï¼è®°å½å°Cacheä¸ï¼çå°äºå¡æ交ï¼committedï¼éè¦æ交çæ¶åï¼åææ¥å¿æä¹ åå°ç£çï¼é»è®¤æ¯Kã
max_binlog_cache_size = M #binlogç¼åæ大使ç¨çå å
max_binlog_size = 2M #ä¸ä¸ªbinlogæ¥å¿ç大å°
expire_logs_days = 7 #ä¿ç7天çbinlog
key_buffer_size = M #ç´¢å¼ç¼å大å°: å®å³å®äºæ°æ®åºç´¢å¼å¤ççé度ï¼å°¤å ¶æ¯ç´¢å¼è¯»çé度
read_buffer_size = M #MySqlè¯»å ¥ç¼å²åºå¤§å°ã对表è¿è¡é¡ºåºæ«æç请æ±å°åé ä¸ä¸ªè¯»å ¥ç¼å²åºï¼MySqlä¼ä¸ºå®åé ä¸æ®µå åç¼å²åºãread_buffer_sizeåéæ§å¶è¿ä¸ç¼å²åºç大å°ãå¦æ对表ç顺åºæ«æ请æ±é常é¢ç¹ï¼å¹¶ä¸ä½ 认为é¢ç¹æ«æè¿è¡å¾å¤ªæ ¢ï¼å¯ä»¥éè¿å¢å 该åéå¼ä»¥åå åç¼å²åºå¤§å°æé«å ¶æ§è½
read_rnd_buffer_size = 2M #MySQLçéæºè¯»ç¼å²åºå¤§å°ãå½æä»»æ顺åºè¯»åè¡æ¶(ä¾å¦ï¼æç §æåºé¡ºåº)ï¼å°åé ä¸ä¸ªéæºè¯»ç¼ååºãè¿è¡æåºæ¥è¯¢æ¶ï¼MySQLä¼é¦å æ«æä¸é该ç¼å²ï¼ä»¥é¿å ç£çæç´¢ï¼æé«æ¥è¯¢é度ï¼å¦æéè¦æåºå¤§éæ°æ®ï¼å¯éå½è°é«è¯¥å¼ãä½MySQLä¼ä¸ºæ¯ä¸ªå®¢æ·è¿æ¥åæ¾è¯¥ç¼å²ç©ºé´ï¼æ以åºå°½ééå½è®¾ç½®è¯¥å¼ï¼ä»¥é¿å å åå¼éè¿å¤§
bulk_insert_buffer_size = 1M #æ¹éæå ¥æ°æ®ç¼å大å°ï¼å¯ä»¥æææé«æå ¥æçï¼é»è®¤ä¸º8M
myisam_sort_buffer_size = 1M #MyISAM表åçååæ¶éæ°æåºæéçç¼å²
myisam_max_sort_file_size = G #MySQLé建索å¼æ¶æå 许çæ大临æ¶æ件çå¤§å° (å½ REPAIR, ALTER TABLE æè LOAD DATA INFILE). å¦ææ件大å°æ¯æ¤å¼æ´å¤§,ç´¢å¼ä¼éè¿é®å¼ç¼å²å建(æ´æ ¢)
myisam_repair_threads = 1 #å¦æä¸ä¸ªè¡¨æ¥æè¶ è¿ä¸ä¸ªç´¢å¼, MyISAM å¯ä»¥éè¿å¹¶è¡æåºä½¿ç¨è¶ è¿ä¸ä¸ªçº¿ç¨å»ä¿®å¤ä»ä»¬.è¿å¯¹äºæ¥æå¤ä¸ªCPU以å大éå åæ åµçç¨æ·,æ¯ä¸ä¸ªå¾å¥½çéæ©.
myisam_recover #èªå¨æ£æ¥åä¿®å¤æ²¡æéå½å ³éç MyISAM 表
lower_case_table_names = 1 #让mysqlä¸åºå大å°å
skip-name-resolve #ç¦ç¨DNS解æï¼è¿æ¥é度ä¼å¿«å¾å¤ãä¸è¿ï¼è¿æ ·çè¯å°±ä¸è½å¨MySQLçææ表ä¸ä½¿ç¨ä¸»æºåäºèåªè½ç¨ipæ ¼å¼ã
#slave-skip-errors = , #è¿æ¯é填项让slaveåºè·³è¿åªäºé误继ç»åæ¥
#replicate-ignore-db=mysql #éå¡«ï¼åæ¥æ¶ååªä¸ªæ°æ®åºä¸åæ¥è®¾ç½®
server-id = 1
innodb_additional_mem_pool_size = 4M #InnoDB åå¨çæ°æ®ç®å½ä¿¡æ¯åå ¶å®å é¨æ°æ®ç»æçå åæ± å¤§å°ãåºç¨ç¨åºéç表è¶å¤ï¼ä½ éè¦å¨è¿éåé è¶å¤çå åï¼é»è®¤æ¯2M
innodb_buffer_pool_size = M #è¿å¯¹Innodb表æ¥è¯´é常éè¦ãInnodbç¸æ¯MyISAM表对ç¼å²æ´ä¸ºææãMyISAMå¯ä»¥å¨é» 认ç key_buffer_size 设置ä¸è¿è¡çå¯ä»¥ï¼ç¶èInnodbå¨é»è®¤ç 设置ä¸å´è·èçä¼¼çãç±äºInnodbææ°æ®åç´¢å¼é½ç¼åèµ·æ¥ï¼æ éçç»æä½ç³»ç»å¤ªå¤çå åï¼å æ¤å¦æåªéè¦ç¨Innodbçè¯åå¯ä»¥è®¾ç½®å®é«è¾¾ -% çå¯ç¨å åãä¸äºåºç¨äº key_buffer çè§åæ â å¦æä½ çæ°æ®éä¸å¤§ï¼å¹¶ä¸ä¸ä¼æ´å¢ï¼é£ä¹æ éæ innodb_buffer_pool_size 设置ç太大äº
innodb_file_io_threads = 4 #æ件IOç线ç¨æ°ï¼ä¸è¬ä¸º 4
innodb_thread_concurrency = 8 #ä½ çæå¡å¨CPUæå 个就设置为å ,建议ç¨é»è®¤ä¸è¬ä¸º8
innodb_flush_log_at_trx_commit = 2 #é»è®¤ä¸º1ï¼å¦æå°æ¤åæ°è®¾ç½®ä¸º1ï¼å°å¨æ¯æ¬¡æ交äºå¡åå°æ¥å¿åå ¥ç£çã为æä¾æ§è½ï¼å¯ä»¥è®¾ç½®ä¸º0æ2ï¼ä½è¦æ¿æ å¨åçæ éæ¶ä¸¢å¤±æ°æ®çé£é©ã设置为0表示äºå¡æ¥å¿åå ¥æ¥å¿æ件ï¼èæ¥å¿æ件æ¯ç§å·æ°å°ç£çä¸æ¬¡ã设置为2表示äºå¡æ¥å¿å°å¨æ交æ¶åå ¥æ¥å¿ï¼ä½æ¥å¿æ件æ¯æ¬¡å·æ°å°ç£çä¸æ¬¡ã
innodb_log_buffer_size = 2M #æ¤åæ°ç¡®å®äºæ¥å¿æ件æç¨çå å大å°ï¼ä»¥M为åä½ãç¼å²åºæ´å¤§è½æé«æ§è½ï¼ä½æå¤çæ éå°ä¼ä¸¢å¤±æ°æ®.MySQLå¼å人å建议设置为1ï¼8Mä¹é´
innodb_log_file_size = 4M #æ¤åæ°ç¡®å®æ°æ®æ¥å¿æ件ç大å°ï¼ä»¥M为åä½ï¼æ´å¤§ç设置å¯ä»¥æé«æ§è½ï¼ä½ä¹ä¼å¢å æ¢å¤æ éæ°æ®åºæéçæ¶é´
innodb_log_files_in_group = 3 #为æé«æ§è½ï¼MySQLå¯ä»¥ä»¥å¾ªç¯æ¹å¼å°æ¥å¿æ件åå°å¤ä¸ªæ件ãæ¨è设置为3M
innodb_max_dirty_pages_pct = #Buffer_Poolä¸Dirty_Pageæå çæ°éï¼ç´æ¥å½±åInnoDBçå ³éæ¶é´ãåæ° innodb_max_dirty_pages_pctå¯ä»¥ç´æ¥æ§å¶äºDirty_Pageå¨Buffer_Poolä¸æå çæ¯çï¼èä¸å¹¸è¿çæ¯ innodb_max_dirty_pages_pctæ¯å¯ä»¥å¨ææ¹åçãæ以ï¼å¨å ³éInnoDBä¹åå è°å°ï¼å¼ºå¶æ°æ®åFlushä¸æ®µæ¶é´ï¼åè½å¤å¤§å¤§ç¼©çMySQLå ³éçæ¶é´ã
innodb_lock_wait_timeout = #InnoDB æå ¶å ç½®çæ»éæ£æµæºå¶ï¼è½å¯¼è´æªå®æçäºå¡åæ»ãä½æ¯ï¼å¦æç»åInnoDB使ç¨MyISAMçlock tables è¯å¥æ第ä¸æ¹äºå¡å¼æ,åInnoDBæ æ³è¯å«æ»éã为æ¶é¤è¿ç§å¯è½æ§ï¼å¯ä»¥å°innodb_lock_wait_timeout设置为ä¸ä¸ªæ´æ°å¼ï¼æ示 MySQLå¨å è®¸å ¶ä»äºå¡ä¿®æ¹é£äºæç»åäºå¡åæ»çæ°æ®ä¹åè¦çå¾ å¤é¿æ¶é´(ç§æ°)
innodb_file_per_table = 0 #ç¬äº«è¡¨ç©ºé´ï¼å ³éï¼
[mysqldump]
quick
max_allowed_packet = M
4. æ¶æä¼å
ï¼1ï¼. å端ç¨memcachedï¼redisçç¼ååæ æ°æ®åºåå
ï¼2ï¼. æ°æ®åºè¯»åå离ï¼è´è½½åè¡¡
ï¼3ï¼. æ°æ®åºååºå表
ï¼4ï¼. åå¨å¯éååå¸å¼
5. åæä¼å
主è¦æ¯å¤è§å¯ï¼åæå°±æ¯ç»´æ¤å·¥ä½äºï¼è§å¯æå¡å¨è´è½½æ¯éè¦æ·»å 硬件äºï¼è¿æ¯æè¯å¥æé®é¢åï¼è¿æ¯åæ°è¦ä¿®æ¹äºã
6. æ¥è¯¢ä¼åï¼ææå«äººçï¼
. 使ç¨æ ¢æ¥è¯¢æ¥å¿å»åç°æ ¢æ¥è¯¢ã
. 使ç¨æ§è¡è®¡åå»å¤ææ¥è¯¢æ¯å¦æ£å¸¸è¿è¡ã
. æ»æ¯å»æµè¯ä½ çæ¥è¯¢ççæ¯å¦ä»ä»¬è¿è¡å¨æä½³ç¶æä¸ âä¹ èä¹ ä¹æ§è½æ»ä¼ååã
. é¿å å¨æ´ä¸ªè¡¨ä¸ä½¿ç¨count(*),å®å¯è½éä½æ´å¼ 表ã
. 使æ¥è¯¢ä¿æä¸è´ä»¥ä¾¿åç»ç¸ä¼¼çæ¥è¯¢å¯ä»¥ä½¿ç¨æ¥è¯¢ç¼åã
. å¨éå½çæ å½¢ä¸ä½¿ç¨GROUP BYèä¸æ¯DISTINCTã
. å¨WHERE, GROUP BYåORDER BYåå¥ä¸ä½¿ç¨æç´¢å¼çåã
. ä¿æç´¢å¼ç®å,ä¸å¨å¤ä¸ªç´¢å¼ä¸å å«åä¸ä¸ªåã
. ææ¶åMySQLä¼ä½¿ç¨é误çç´¢å¼,对äºè¿ç§æ åµä½¿ç¨USE INDEXã
. æ£æ¥ä½¿ç¨SQL_MODE=STRICTçé®é¢ã
. 对äºè®°å½æ°å°äº5çç´¢å¼å段ï¼å¨UNIONçæ¶å使ç¨LIMITä¸æ¯æ¯ç¨OR.
. ä¸ºäº é¿å å¨æ´æ°åSELECTï¼ä½¿ç¨INSERT ON DUPLICATE KEYæè INSERT IGNORE ,ä¸è¦ç¨UPDATEå»å®ç°ã
. ä¸è¦ä½¿ç¨ MAX,使ç¨ç´¢å¼å段åORDER BYåå¥ã
. é¿å 使ç¨ORDER BY RAND().
ãLIMIT Mï¼Nå®é ä¸å¯ä»¥åç¼æ¥è¯¢å¨æäºæ åµä¸ï¼æèå¶å°ä½¿ç¨ã
ãå¨WHEREåå¥ä¸ä½¿ç¨UNION代æ¿åæ¥è¯¢ã
ã对äºUPDATESï¼æ´æ°ï¼ï¼ä½¿ç¨ SHARE MODEï¼å ±äº«æ¨¡å¼ï¼ï¼ä»¥é²æ¢ç¬å éã
ãå¨éæ°å¯å¨çMySQLï¼è®°å¾æ¥æ¸©æä½ çæ°æ®åºï¼ä»¥ç¡®ä¿æ¨çæ°æ®å¨å ååæ¥è¯¢é度快ã
ã使ç¨DROP TABLEï¼CREATE TABLE DELETE FROMä»è¡¨ä¸å é¤æææ°æ®ã
ãæå°åçæ°æ®å¨æ¥è¯¢ä½ éè¦çæ°æ®ï¼ä½¿ç¨*æ¶è大éçæ¶é´ã
ãèèæä¹ è¿æ¥ï¼èä¸æ¯å¤ä¸ªè¿æ¥ï¼ä»¥åå°å¼éã
ãåºåæ¥è¯¢ï¼å æ¬ä½¿ç¨æå¡å¨ä¸çè´è½½ï¼ææ¶ä¸ä¸ªç®åçæ¥è¯¢å¯ä»¥å½±åå ¶ä»æ¥è¯¢ã
ãå½è´è½½å¢å æ¨çæå¡å¨ä¸ï¼ä½¿ç¨SHOW PROCESSLISTæ¥çæ ¢çåæé®é¢çæ¥è¯¢ã
ãå¨å¼åç¯å¢ä¸äº§ççéåæ°æ®ä¸ æµè¯çææå¯ççæ¥è¯¢ã
如何杀掉空闲事务
本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: /tech/database/how_to_kill_idle_trx.html 我们经常遇到一个情况,就是网络断开或程序Bug导致COMMIT/ROLLBACK语句没有传到数
本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: /tech/database/how_to_kill_idle_trx.html
我们经常遇到一个情况,就是网络断开或程序Bug导致COMMIT/ROLLBACK语句没有传到数据库,也没有释放线程,但是线上事务锁定等待严重,连接数暴涨,尤其在测试库这种情况很多,线上也偶有发生,于是想为MySQL增加一个杀掉空闲事务的功能。
那么如何实现呢,通过MySQL Server层有很多不确定因素,最保险还是在存储引擎层实现,我们用的几乎都是InnoDB/XtraDB,所以就基于Percona来修改了,Oracle版的MySQL也可以照着修改。
需求:
1. 一个事务启动,如果事务内最后一个语句执行完超过一个时间(innodb_idle_trx_timeout),就应该关闭链接。
2. 如果事务是纯读事务,因为不加锁,所以无害,不需要关闭,保持即可。
虽然这个思路被Percona的指出Alexey Kopytov可能存在“Even though SELECT queries do not place row locks by default (there are exceptions), they can still block undo log records from being purged.”的问题,但是我们确实有场景SELECT是绝对不能kill的,除非之后的INSERT/UPDATE/DELETE发生了,所以我根据我们的业务特点来修改。
跟Percona的Yasufumi Kinoshita和Alexey Kopytov提出过纯SELECT事务不应被kill,但通过一个参数控制的方案还没有被Alexey Kopytov接受,作为通用处理我提出了用两个变量分别控制纯读事务的空闲超时时间和有锁事务的空闲超时时间,还在等待Percona的回复,因为这个方案还在测试,就先不开放修改了,当然如果你很熟悉MYSQL源码,我提出这个思路你肯定知道怎么分成这两个参数控制了。
根据这两个需求我们来设计方法,首先想到这个功能肯定是放在InnoDB Master Thread最方便,Master Thread每秒调度一次,可以顺便检查空闲事务,然后关闭,因为在事务中操作trx->mysql_thd并不安全,所以一般来说最好在InnoDB层换成Thread ID操作,并且InnoDB中除了ha_innodb.cc,其他地方不能饮用THD,所以Master Thread中需要的线程数值,都需要在ha_innodb中计算好传递整型或布尔型返回值给master thread调用。
首先,我们要增加一个参数:idle_trx_timeout,它表示事务多久没有下一条语句发生就超时关闭。
在storage/innodb_plugin/srv/srv0srv.c的“/* plugin options */”注释下增加如下代码注册idle_trx_timeout变量。
static MYSQL_SYSVAR_LONG(idle_trx_timeout, srv_idle_trx_timeout,
PLUGIN_VAR_RQCMDARG,
"If zero then this function no effect, if no-zero then wait idle_trx_timeout seconds this transaction will be closed",
"Seconds of Idle-Transaction timeout",
NULL, NULL, 0, 0, LONG_MAX, 0);
代码往下找在innobase_system_variables结构体内加上:
MYSQL_SYSVAR(idle_trx_timeout),
有了这个变量,我们需要在Master Thread(storage/innodb_plugin/srv/srv0srv.c )中执行检测函数查找空闲事务。在loop循环的if (sync_array_print_long_waits(&waiter, &sema)判断后加上这段判断
if (srv_idle_trx_timeout && trx_sys) {
trx_t* trx;
time_t now;
rescan_idle:
now = time(NULL);
mutex_enter(&kernel_mutex);
trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list); # 从当前事务列表里获取第一个事务
while (trx) { # 依次循环每个事务进行检查
if (trx->conc_state == TRX_ACTIVE
&& trx->mysql_thd
&& innobase_thd_is_idle(trx->mysql_thd)) { # 如果事务还活着并且它的状态时空闲的
ib_int_t start_time = innobase_thd_get_start_time(trx->mysql_thd); # 获取线程最后一个语句的开始时间
ulong thd_id = innobase_thd_get_thread_id(trx->mysql_thd); #获取线程ID,因为存储引擎内直接操作THD不安全
if (trx->last_stmt_start != start_time) { # 如果事务最后语句起始时间不等于线程最后语句起始时间说明事务是新起的
trx->idle_start = now; # 更新事务的空闲起始时间
trx->last_stmt_start = start_time; # 更新事务的最后语句起始时间
} else if (difftime(now, trx->idle_start) # 如果事务不是新起的,已经执行了一部分则判断空闲时间有多长了
> srv_idle_trx_timeout) { # 如果空闲时间超过阈值则杀掉链接
/* kill the session */
mutex_exit(&kernel_mutex);
thd_kill(thd_id); # 杀链接
goto rescan_idle;
}
}
trx = UT_LIST_GET_NEXT(mysql_trx_list, trx); # 检查下一个事务
}
mutex_exit(&kernel_mutex);
}
其中trx中的变量是新加的,在storage/innodb_plugin/include/trx0trx.h的trx_truct加上需要的变量:
struct trx_struct{
...
time_t idle_start;
ib_int_t last_stmt_start;
...
}
这里有几个函数是自定义的:
ibool innobase_thd_is_idle(const void* thd);
ib_int_t innobase_thd_get_start_time(const void* thd);
ulong innobase_thd_get_thread_id(const void* thd);
这些函数在ha_innodb.cc中实现,需要在storage/innodb_plugin/srv/srv0srv.c头文件定义下加上这些函数的引用形势。
然后在storage/innodb_plugin/handler/ha_innodb.cc 中定义这些函数的实现:
extern "C"
ibool
innobase_thd_is_idle(
const void* thd) /*!{
return(((const THD*)thd)->command == COM_SLEEP);
}
extern "C"
ib_int_t
innobase_thd_get_start_time(
const void* thd) /*!{
return((ib_int_t)((const THD*)thd)->start_time);
}
extern "C"
ulong
innobase_thd_get_thread_id(
const void* thd)
{
return(thd_get_thread_id((const THD*) thd));
}
还有最重要的thd_kill函数负责杀线程的,在sql/sql_class.cc中,找个地方定义这个函数:
void thd_kill(ulong id)
{
THD *tmp;
VOID(pthread_mutex_lock(&LOCK_thread_count));
I_List_iterator it(threads);
while ((tmp=it++))
{
if (tmp->command == COM_DAEMON || tmp->is_have_lock_thd == 0 ) # 如果是DAEMON线程和不含锁的线程就不要kill了
continue;
if (tmp->thread_id == id)
{
pthread_mutex_lock(&tmp->LOCK_thd_data);
break;
}
}
VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (tmp)
{
tmp->awake(THD::KILL_CONNECTION);
pthread_mutex_unlock(&tmp->LOCK_thd_data);
}
}
为了存储引擎能引用到这个函数,我们要把它定义到plugin中:
include/mysql/plugin.h和include/mysql/plugin.h中加上
void thd_kill(unsigned long id);
如何判定线程的is_have_lock_thd值?首先在THD中加上这个变量(sql/sql_class.cc):
class THD :public Statement,
public Open_tables_state
{
....
uint is_have_lock_thd;
....
}
然后在SQL的必经之路mysql_execute_command拦上一刀,判断是有锁操作发生了还是事务提交或新起事务。
switch (lex->sql_command) {
case SQLCOM_REPLACE:
case SQLCOM_REPLACE_SELECT:
case SQLCOM_UPDATE:
case SQLCOM_UPDATE_MULTI:
case SQLCOM_DELETE:
case SQLCOM_DELETE_MULTI:
case SQLCOM_INSERT:
case SQLCOM_INSERT_SELECT:
thd->is_have_lock_thd = 1;
break;
case SQLCOM_COMMIT:
case SQLCOM_ROLLBACK:
case SQLCOM_XA_START:
case SQLCOM_XA_END:
case SQLCOM_XA_PREPARE:
case SQLCOM_XA_COMMIT:
case SQLCOM_XA_ROLLBACK:
case SQLCOM_XA_RECOVER:
thd->is_have_lock_thd = 0;
break;
}
为了尽可能兼容Percona的补丁,能引用的都引用了Percona的操作,有些函数调用是在层次太多看不下去了就简化了。
另外还有一个版本是我自己弄的,在THD中增加了一个last_sql_end_time,在do_command结束后更新last_sql_end_time,然后在事务中拿到THD查看last_sql_end_time就可以得出idle时间,Oracle版我还是建议这么做,不要去改trx_struct结构体了,那个感觉更危险。
MySQL 核心模块揭秘 | 期 | 创建 savepoint
回滚操作,除了回滚整个事务,还可以部分回滚。部分回滚,需要保存点(savepoint)的协助。本文我们先看看保存点里面都有什么。
作者:操盛春,爱可生技术专家,公众号『一树一溪』作者,专注于研究 MySQL 和 OceanBase 源码。 爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源
本文基于 MySQL 8.0. 源码,存储引擎为 InnoDB。
InnoDB 的事务对象有一个名为undo_no 的属性。事务每次改变(插入、更新、删除)某个表的一条记录,都会产生一条 undo 日志。这条 undo 日志中会存储它自己的序号。这个序号就来源于事务对象的 undo_no 属性。
也就是说,事务对象的 undo_no 属性中保存着事务改变(插入、更新、删除)某个表中下一条记录产生的 undo 日志的序号。
每个事务都维护着各自独立的 undo 日志序号,和其它事务无关。
每个事务的 undo 日志序号都从 0 开始。事务产生的第 1 条 undo 日志的序号为 0,第 2 条 undo 日志的序号为 1,依此类推。
InnoDB 的 savepoint 结构中会保存创建 savepoint 时事务对象的 undo_no 属性值。
我们通过 SQL 语句创建一个 savepoint 时,server 层、binlog、InnoDB 会各自创建用于保存 savepoint 信息的结构。
server 层的 savepoint 结构是一个SAVEPOINT 类型的对象,主要属性如下:
binlog 的 savepoint 结构很简单,是一个 8 字节的整数。这个整数的值,是创建 savepoint 时事务已经产生的 binlog 日志的字节数,也是接下来新产生的 binlog 日志写入 trx_cache 的 offset。
为了方便介绍,我们把这个整数值称为binlog offset。
InnoDB 的 savepoint 结构是一个trx_named_savept_t 类型的对象,主要属性如下:
创建 savepoint 时,server 层会分配一块 字节的内存,除了存放它自己的 SAVEPOINT 对象,还会存放 binlog offset 和 InnoDB 的 trx_named_savept_t 对象。
server 层的 SAVEPOINT 对象占用这块内存的前 字节,InnoDB 的 trx_named_savept_t 对象占用中间的 字节,binlog offset 占用最后的 8 字节。
客户端连接到 MySQL 之后,MySQL 会分配一个专门用于该连接的用户线程。
用户线程中有一个m_savepoints 链表,用户创建的多个 savepoint 通过 prev 属性形成链表,m_savepoints 就指向最新创建的 savepoint。
server 层创建 savepoint 之前,会按照创建时间从新到老,逐个查看链表中是否存在和本次创建的 savepoint 同名的 savepoint。
如果在用户线程的 m_savepoints 链表中找到了和本次创建的 savepoint 同名的 savepoint,需要先删除 m_savepoints 链表中的同名 savepoint。
找到的同名 savepoint,是 server 层的SAVEPOINT 对象,它后面的内存区域分别保存着 InnoDB 的 trx_named_savept_t 对象、binlog offset。
binlog 是个老实孩子,乖乖的把 binlog offset 写入了 server 层为它分配的内存里。删除同名 savepoint 时,不需要单独处理 binlog offset。
InnoDB 就不老实了,虽然 server 层也为 InnoDB 的 trx_named_savept_t 对象分配了内存,但是 InnoDB 并没有往里面写入内容。
事务执行过程中,用户每次创建一个 savepoint,InnoDB 都会创建一个对应的 trx_named_savept_t 对象,并加入 InnoDB 事务对象的 trx_savepoints 链表的末尾。
因为 InnoDB 自己维护了一个存放 savepoint 结构的链表,server 层删除同名 savepoint 时,InnoDB 需要找到这个链表中对应的 savepoint 结构并删除,流程如下:
InnoDB 从事务对象的 trx_savepoints 链表中删除 trx_named_savept_t 对象之后,server 层接着从用户线程的 m_savepoints 链表中删除 server 层的SAVEPOINT 对象,也就连带着清理了 binlog offset。
处理完查找、删除同名 savepoint 之后,server 层就正式开始创建 savepoint 了,这个过程分为 3 步。
第 1 步,binlog 会生成一个 Query_log_event。
以创建名为test_savept 的 savepoint 为例,这个 event 的内容如下:
binlog event 写入 trx_cache 之后,binlog offset 会写入 server 层为它分配的 8 字节的内存中。
第 2 步,InnoDB 创建 trx_named_savept_t 对象,并放入事务对象的 trx_savepoints 链表的末尾。
trx_named_savept_t 对象的 name 属性值是 InnoDB 的 savepoint 名字。这个名字是根据 server 层为 InnoDB 的 trx_named_savept_t 对象分配的内存的地址计算得到的。
trx_named_savept_t 对象的savept 属性,是一个 trx_savept_t 类型的对象。这个对象里保存着创建 savepoint 时,事务对象中 undo_no 属性的值,也就是下一条 undo 日志的序号。
第 3 步,把 server 层的 SAVEPOINT 对象加入用户线程的 m_savepoints 链表的尾部。
server 层会创建一个SAVEPOINT 对象,用于存放 savepoint 信息。
binlog 会把binlog offset 写入 server 层为它分配的一块 8 字节的内存里。
InnoDB 会维护自己的 savepoint 链表,里面保存着trx_named_savept_t 对象。
如果 m_savepoints 链表中存在和本次创建的 savepoint 同名的 savepoint, 创建新的 savepoint 之前,server 层会从链表中删除这个同名的 savepoint。
server 层创建的 SAVEPOINT 对象会放入m_savepoints 链表的末尾。
InnoDB 创建的 trx_named_savept_t 对象会放入事务对象的trx_savepoints 链表的末尾。
tron货币什么情况
TRON货币目前处于加密货币市场的活跃状态。 TRON是一种基于区块链技术的开放源代码项目,旨在构建一个全球性的自由内容娱乐系统。其货币TRONIX是该生态系统中的数字代币,主要用于平台上的交易和支付。自推出以来,TRON和TRX都受到了市场的广泛关注,特别是在数字货币领域有着一定的影响力。TRON的工作重点是提供一种可行的方案来构建自由、即时和开放的互联网环境。这个项目的进展也持续引发业界和投资者的兴趣。而具体表现如何,还需结合市场情况进行分析。 TRON货币的市场表现 TRON货币的市场表现与全球加密货币市场紧密相关。在全球市场积极的氛围下,TRON货币的价格可能上涨,并受到更多投资者的追捧。随着越来越多的商家和企业开始接受TRX作为支付方式,其实际应用场景也在不断扩大。此外,TRON生态系统中的其他应用和服务也为其货币的普及提供了支持。然而,与其他加密货币一样,TRX的价格也存在波动性,受到市场需求、监管政策和技术发展等多种因素的影响。投资者在参与时应当充分了解和评估风险。 TRON的技术发展和社区支持 除了市场表现外,TRON的技术发展和社区支持也是其成功的重要因素。TRON团队一直在努力优化其区块链技术,提高系统的可扩展性和性能。此外,拥有一个活跃的社区也是项目成功的重要推动力。社区成员可以通过各种渠道交流和分享经验,为项目提供宝贵的反馈和建议。这些都有助于推动TRON货币的长远发展。因此总体来看,TRON货币具有发展潜力但也存在风险,投资者需审慎判断。请注意投资有风险,决策需谨慎。2024-12-28 18:51
2024-12-28 18:30
2024-12-28 17:22
2024-12-28 17:17
2024-12-28 16:27