阿里MySQL内核月报

六 12th, 2015 | Posted by | Filed under 数据库

有同学问为什么我好久没写MySQL文章了,其实不是没写,是都写到咱们阿里云RDS MySQL数据库内核月报了,下面是地址。
Somebody asks me: why are you not writing mysql posts so long? In fact, it’s not my lazy, because of I post my research on  <Aliyun RDS MySQL Database Kernel Monthly>. Following are URLs:

比较旧的归档在这里:
Older archives here:
http://mysql.taobao.org/index.php?title=%E8%B5%84%E6%96%99%E5%85%B1%E4%BA%AB#MySQL_.E5.86.85.E6.A0.B8.E6.9C.88.E6.8A.A5

新的月报都在这里可以看到:
And new posts here:
http://mysql.taobao.org/monthly/

我有空也会挑选一些很有价值的翻译成英文,给外国朋友们看。
If I’m free, I will choose some valuable articles from our  <Aliyun RDS MySQL Database Kernel Monthly> to translate to English for foreign friends. :-)

标签:

一些Git操作的技巧

六 12th, 2015 | Posted by | Filed under 程序设计

最近1年开发从SVN/Bzr换到了Git,总得来说Git还是很好用的,这里总结了一些不错的命令。

git stash

我们有时会遇到这样的情况,正在分支a上开发一半,然后分支b上发现Bug,需要马上处理。
这时候分支a上的修改怎么办呢,git add 是不行的,有的git客户端版本会提示还有add过的文件没提交不能切换分支,有的git客户端版本会把修改带到b分支。

git stash 就是解决这个问题,它把当前工作区的修改和git add的内容都保存到一个地方,然后git reset HEAD,使工作区回到上一次提交,处于干净状态。然后就可以很放心的切到另外的分支b干活了。

git stash save “先给我保存一下,我要去别的分支修bug”
git stash list
git stash pop
git stash apply stash@{num}

git rebase

有的时候我们在一个分支a开发的时候,master已经进入了很多修改,这时候如果把a的修改提交上去,可能就会跟主干有冲突,需要在主干解决冲突才能提交,这样比较难看。

这时候git rebase就有用了,git rebase BRANCH_NAME可以把BRANCH_NAME分支的修改带到当前分支来,这样当前分支就有了BRANCH_NAME分支的所有内容,这样在当前分支开发的内容提交以后不会跟BRANCH_NAME有冲突,冲突在当前分支就可以解决。

git reset

可以取消已经提交的commit,一般我们只用git reset HEAD^。因为每个分支可能开发过程中为了保存过程以便回溯会有很多commit,但是我们要求进入主干时,每个功能和bugfix只能有一个提交,因此可以先用git reset退回到最早的commit,然后把自己的修改最后打包成一个commit,再去跟主干合并。

利用这两个命令,我们可以很好的管理我们的MySQL开发。我们只有一个master分支作为主干,不允许在主干上直接开发。每个同学根据feature和bug的issue建立分支,然后在分支上开发,不管开发过程中有多少个commit,我们要求最终提交每个bugfix或feature只能有一个提交。因此每个同学完成开发后,都需要git reset 退到最早的commit,git stash save宝存一下自己的修改,然后git checkout master; git pull拖一下最新的主干,然后返回自己的分支,再做git rebase master,把当前分支推进到主干,最后git stash pop弹出修改,有冲突则在当前分支解决,再git push。

标签:

RDS 高可用保障之 – 隐式主键

四 22nd, 2014 | Posted by | Filed under 数据库

原文发在:阿里云产品博客

 

在构建稳定可靠的应用架构时, 数据库是最底层、最稳定的组件之一;而在云环境中,RDS 提供一个7*24小时不间接访问的云服务,可用性达到99.95%.

RDS 采用主备复制架构,用户购买一个实例,RDS都会提供一个性能对等的备库用于保证高可用。 高可用性组件(AURORA)会每3秒检查主库(Master)状态,当发现 Master 出现Down机时可以将用户的SQL请求快速转移到备库(Slave)上面。


rds-1

阅读全文…

标签:

迁移Bzr代码库到Git库中

四 18th, 2014 | Posted by | Filed under 项目管理

最近连续做了两次任务,都是把Bzr的代码转移到Git中,这里记录一下操作步骤。

目标:把MariaDB 10.0.10的GA版本代码库导入公司的Gitlab中。

这里需要用到bzr的fastimport工具,可以从lp上获得最新的代码,放在bzr的plugin目录下。

➜ /Users/plx >cd ~/.bazaar/plugins
➜ /Users/plx/.bazaar/plugins >bzr branch lp:bzr-fastimport fastimport

然后执行bzr selftest fastimport会提示你python缺乏各种包,用easy_install安装即可。
特别注明的是,python-fastimport包必须安装0.92以下版本,否则跟bzr-fastimport不兼容,会缺少两个函数。

然后查看MariaDB 10.0.10版本对应的版本号,通过tag来查询:

➜ /Users/plx/Documents/Code/MariaDB/mariadb-10 >bzr tags | grep 10.0.10
mariadb-10.0.10      4140

这里可以看到10.0.10版本对应的tag号为4140,然后我们导出一份4140版本号的代码来操作。

bzr branch -r4140 lp:maria

完成之后就可以用bzr-fastimport工具了:

cd maria
git init
bzr fast-export --plain . | git fast-import

Gitlab上已经创建好一个m_10010的空项目,转换完成之后就可以上传到Gitlab了:

rm -rf bzr
rm -rf .bzr*
git remote add origin git@gitlab.alibaba-inc.com:m/m_10010.git
git push --mirror git@gitlab.alibaba-inc.com:m/m_10010.git

完成!

标签: , ,

MySQL中无GROUP BY直接HAVING的问题

八 8th, 2013 | Posted by | Filed under 数据库

今天有同学给我反应,有一张表,id是主键,这样的写法可以返回一条记录:

“SELECT * FROM t HAVING id=MIN(id);”

但是只是把MIN换成MAX,这样返回就是空了:

“SELECT * FROM t HAVING id=MAX(id);”

这是为什么呢?

我们先来做个试验,验证这种情况。
这是表结构,初始化两条记录,然后试验:

root@localhost : plx 10:25:10> show create table t2\G
*************************** 1. row ***************************
       Table: t2
Create Table: CREATE TABLE `t2` (
  `a` int(11) DEFAULT NULL,
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
 
root@localhost : plx 10:25:15> select * from t2;
+------+----+
| a    | id |
+------+----+
|    1 |  1 |
|    1 |  3 |
+------+----+
2 rows in set (0.00 sec)
 
root@localhost : plx 10:25:20> SELECT * FROM t2 HAVING id=MIN(id);
+------+----+
| a    | id |
+------+----+
|    1 |  1 |
+------+----+
1 row in set (0.00 sec)
 
root@localhost : plx 10:25:30> SELECT * FROM t2 HAVING id=MAX(id);
Empty set (0.00 sec)

初看之下,好像真的是这样哎,怎么会这样呢?

我再试一下,把a字段改一个为10,然后试下a字段:

root@localhost : plx 10:26:58> select * from t2;
+------+----+
| a    | id |
+------+----+
|   10 |  1 |
|    1 |  3 |
+------+----+
2 rows in set (0.00 sec)
 
root@localhost : plx 10:28:20> SELECT * FROM t2 HAVING a=MAX(a);
+------+----+
| a    | id |
+------+----+
|   10 |  1 |
+------+----+
1 row in set (0.00 sec)
 
root@localhost : plx 10:28:28> SELECT * FROM t2 HAVING a=MIN(a);
Empty set (0.00 sec)

我擦,这回MAX能返回,MIN不能了,这又是为啥呢?

旁白
一般来说,HAVING子句是配合GROUP BY使用的,单独使用HAVING本身是不符合规范的,
但是MySQL会做一个重写,加上一个GROUP BY NULL,”SELECT * FROM t HAVING id=MIN(id)”会被重写为”SELECT * FROM t GROUP BY NULL HAVING id=MIN(id)”,这样语法就符合规范了。

继续……
但是,这个 GROUP BY NULL 会产生什么结果呢?经过查看代码和试验,可以证明,GROUP BY NULL 等价于 LIMIT 1:

root@localhost : plx 10:25:48> SELECT * FROM t2 GROUP BY NULL;
+------+----+
| a    | id |
+------+----+
|   10 |  1 |
+------+----+
1 row in set (0.00 sec)

也就是说,GROUP BY NULL 以后,只会有一个分组,里面就是第一行数据。
但是如果这样,MIN、MAX结果应该是一致的,那也不应该MAX和MIN一个有结果,一个没结果啊,这是为什么呢,再做一个测试。
修改一下数据,然后直接查看MIN/MAX的值:

root@localhost : plx 10:26:58> select * from t2;
+------+----+
| a    | id |
+------+----+
|   10 |  1 |
|    1 |  3 |
+------+----+
2 rows in set (0.00 sec)
 
root@localhost : plx 10:27:04> SELECT * FROM t2 GROUP BY NULL;
+------+----+
| a    | id |
+------+----+
|   10 |  1 |
+------+----+
1 row in set (0.00 sec)
 
root@localhost : plx 10:30:21> SELECT MAX(a),MIN(a),MAX(id),MIN(id) FROM t2 GROUP BY NULL;
+--------+--------+---------+---------+
| MAX(a) | MIN(a) | MAX(id) | MIN(id) |
+--------+--------+---------+---------+
|     10 |      1 |       3 |       1 |
+--------+--------+---------+---------+
1 row in set (0.00 sec)

是不是发现问题了?
MAX/MIN函数取值是全局的,而不是LIMIT 1这个分组内的。
因此,当GROUP BY NULL的时候,MAX/MIN函数是取所有数据里的最大和最小值!

所以啊,”SELECT * FROM t HAVING id=MIN(id)”本质上是”SELECT * FROM t HAVING id=1″, 就能返回一条记录,而”SELECT * FROM t HAVING id=MAX(id)”本质上是”SELECT * FROM t HAVING id=3″,当然没有返回记录,这就是问题的根源。

测试一下GROUP BY a,这样就对了,每个分组内只有一行,所以MAX/MIN一样大,这回是取得组内最大和最小值。

root@localhost : plx 11:29:49> SELECT MAX(a),MIN(a),MAX(id),MIN(id) FROM t2 GROUP BY a;
+--------+--------+---------+---------+
| MAX(a) | MIN(a) | MAX(id) | MIN(id) |
+--------+--------+---------+---------+
|      1 |      1 |       3 |       3 |
|     10 |     10 |       5 |       5 |
+--------+--------+---------+---------+
2 rows in set (0.00 sec)

GROUP BY NULL时MAX/MIN的行为,是这个问题的本质,所以啊,尽量使用标准语法,玩花样SQL之前,一定要搞清楚它的行为是否与理解的一致。

Enjoy MySQL!