MyISAM表一例查询性能问题排查

问题背景

线上相同结构的两个MyISAM表,数据量差不多,执行的SQL查询计划基本一致,但是执行时间却相差很大

mysql> select * from auction_info_d__201402 where unit_id=7016 and day='2014-03-27';
Empty set (0.31 sec)
mysql> select * from auction_info_d__201403 where unit_id=7016 and day='2013-03-27';
Empty set (19.81 sec)

MySQL版本:

mysql> select @@version;
+------------+
| @@version  |
+------------+
| 5.1.48-log |
+------------+
1 row in set (0.00 sec)

[……]

继续阅读

SELECT…FROM UPDATE 特性介绍及性能测试

使用背景:

将update+select两条SQL合并成单条SQL,向客户端直接返回update之后的结果列,通过减小网络开销及sql解析代价提高性能

特性描述:

postgresql的语法是returning … as …

http://www.postgresql.org/docs/9.1/static/sql-update.html

oracle的语法是returning…into…

http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/returninginto_clause.htm#LNPLS01354

MySQL中由于需要兼容MySQL JDBC,我们将这个特性实现为:SELECT…FROM UPDATE…

[……]

继续阅读

MySQL threadpool(优先队列)介绍及性能测试

背景介绍

MySQL常用(目前线上使用)的线程调度方式是one-thread-per-connection(每连接一个线程),server为每一个连接创建一个线程来服务,连接断开后,这个线程进入thread_cache或者直接退出(取决于thread_cache设置及系统当前已经cache的线程数目),one-thread-per-connection调度的好处是实现简单,而且能够在系统没有遇到瓶颈之前保证较小的响应时间,比较适合活跃的长连接的应用场景,而在大量短连接或者高并发情况下,one-thread-per-connection需要创建/调度大量的线程,产生较高的的context-switch代价,从而使得系统性能下降
[……]

继续阅读

MySQL semi-sync 实现原理分析

本文分析基于Oracle MySQL 5.6.15版本源码,是在阅读MySQL源码以及印风博客基础上总结的,作为新年的第一篇博文,总结去年底的一点学习所得,将重点总结以下内容:
1). binlog group commit
2). semi-sync replication

binlog group commit

这是一个很古老的问题,简单啰嗦一下:为了保证数据安全,事务提交时需要将binlog刷盘,这个其实是分为2歩来做的,write和fsync,其中第二步保证数据持久化,非常耗时,会成为性能瓶颈,如果每提交一个事务都做一次fsync,系统TPS将会大大降低,为了解决这个问题,需要减少fsyn调用的次数,原理:活跃系统中,在一个线程做fsync时,其它线程将等待,等待过程中从这些线程中选出一个leader(进入等待的第一个线程),其它线程由leader代为完成write+fync,leader完成工作后通知所有等待的线程继续运行
[……]

继续阅读

MySQL自我保护与并发优化

问题背景

线上MySQL在大促时遇到并发压力大导致threads_running(并发执行query的线程数目)飙升,MySQL出现性能抖动问题甚至hang住,虽然在InnoDB层有innodb_thread_concurrency限制同时进入InnoDB存储层读写数据的线程数,但是这个参数不是一个硬限制(线程在锁等待结束后强制进入InnoDB层),而且代码路径比较靠后,作用有限,于尝试在server层限制并发数来解决这个问题,通过不断地优化和测试,开发完成了一个高水位限流/低水位优化的patch

patch功能介绍

这个patch是在之前thread running control的基础上优化的,将之前位于同一个函数中两个功能独立出来并将之前低水位限流实现从基于sleep-retry的机制优化成基于FIFO的cond-wait/signal机制
[……]

继续阅读

InnoDB并发控制模型

赶在2014之前,写下2013最后一篇技术博客,介绍一下InnDB的并发控制模型

背景知识

InnoDB中为什么需要并发控制?要回答这个问题,需要先聊聊context switch,当同时执行的进程/线程超过cpu核心数(超线程的数目)时,cpu以时间片轮转调度执行多个进程的时候就有context switch了,当进程A的时间片用完需要调度另外进程B时,需要将进程A的状态和参数保存在堆栈中,等再次调度到A时,再从堆栈中恢复状态和参数,这个切换的代价就是context switch,context switch的代价根据CPU性能及进程空间大小的不同,开销从几微秒(us)到几毫秒(ms)级别(参考:Quantifying The Cost of Context Switchhow-long-does-it-take-to-make-context),相对于一次内存读写操作(100ns左右),context switch代价不可小视(按照100us计算的话,相当于1000次内存访问)
[……]

继续阅读

InnoDB使用linux native aio源码分析

好记性不如烂笔头,这篇文章是一个学习和总结,包括linux native aio API介绍以及InnoDB中如何使用native aio

异步io

linux上异步io有两套API,posix aio和native aio,其中native aio具有更好的性能,但要求文件打开方式必须是O_DIRECT,简单列下两套API的接口:
[table caption="posix aio" width="500" colwidth="80|420" colalign="left|left" border="1"]
function,desc
aio_read,发起一个异步读请求
aio_write,发起一个异步写请求
aio_return,阻塞等待异步io请求返回
aio_error,检查异步io返回结果
aio_suspend,挂起调用进程,直到一个或多个异步请求已经完成(或失败)
aio_cancel,取消异步io
lio_listio,发起一系列异步io请求
[/table][……]

继续阅读

使用DEBUG_SYNC排查MySQL truncate问题

线上问题

DBA用脚本发送truncate操作清理MySQL表中数据,脚本执行一段时间使用ctrl+c想取消操作,却导致slave同步binlog后数据不一致,复制中断,之后通过select发现master表中数据依旧存在,但是truncate对应的binlog被记录记录,而slave中的表数据被清理,因为binlog复制过来后truncate操作执行成功

重现问题

这个问题比较诡异,truncate实际上是失败,但是binlog记录下来,我们知道binlog记录一个完整事务,只有当事务成功执行完才会写binlog,只有问题能够重现才可能找到原因,遂测试truncate发送后马上ctrl+c取消,然而每次truncate都成功,表中数据被清理,binlog也记录下来,后来思考DBA当时使用的是脚本,发送的是多条truncat操作,这样的话可以让truncate执行过程中被打断的位置尽可能的多,这样复现问题的可能性也高一些,经过多轮尝试,终于重现了:[……]

继续阅读

Pthread mutex与GCC atomic性能测试

问题背景

之前对这一块只有一个初步的理解,阅读过一些文章,大概知道pthread中mutex一次加锁时间在10~100ns之间,直觉上认为这个效率非常高了,最近做MySQL高并发优化工作后,发现自己知道的太少,以致浪费了不少时间,遂决定通过测试总结一下最近学习到的东西

mutex的主要作用是保证原子性操作,pthread实现提供的一套api非常简洁,对于一般的应用肯定是够了,但是对于Database这种对性能有变态要求的系统,尤其是在高并发下,需要进一步优化,这时需要用到gcc提供的__sync_xxx_and_fetch系列函数了,具体参考:GCC Atomic Memory Access and built-in functions,这系列函数使用内存屏障保证对内存单元的原子操作,性能较pthread好,本文通过一系列测试得出定量结论
[……]

继续阅读

InnoDB 读写锁rw_lock_t实现

10月忙得像shi一样,不管怎样,忙里偷闲在这个月结束之前写上一篇,介绍InnoDB读写锁的实现

InnoDB读写锁特点

1. 读与读之间不冲突,读与写,写与写之间冲突,这个是读写锁最基本的特征
2. 申请写锁时,如果锁被读持有,将发生写锁等待,该写锁之后的所有读锁会等待该写锁成功获取后才能申请成功,这保证了公平:写锁请求不会被饿死

基本数据结构

sync_array_struct: 保存用于线程同步结构的数组,数组成员类型为sync_cell_struct
sync_cell_struct: 一个线程同步结构体,部分代码:[……]

继续阅读