INSERT ... ON DUPLICATE KEY UPDATE 是非常强大但是往往被遗忘的mysql的功能。它在mysql4.1的时候引入,但我仍然不断见到人们不知道它。
我自己是很喜欢这个功能的,因为它的设计是真正mysql风格的----对于常见任务的提供高效解决方案,同时保持优雅和易用。
这个功能好在哪儿呢?它可以很好的处理任何类型的计数统计。对于流量的统计,它可以记下通过特定的端口或者ip地址的流量和包数;对于web应用,可以记下每个页面或者ip的访问次数,特定关键字被搜索的次数等等。
这个功能也让增量单一通过日志文件的处理(incremental single pass log file processing )和创建汇总表变得简单。
看下面这个例子:
SQL:
CREATE TABLE ipstat(ip int UNSIGNED NOT NULL PRIMARY KEY,
hits int UNSIGNED NOT NULL,
last_hit timestamp);
INSERT INTO ipstat VALUES(inet_aton('192.168.0.1'),1,now())
ON duplicate KEY UPDATE hits=hits+1;
这个例子其实展示了mysql一个更简洁的特性--inet_aton 和inet_ntoa 函数,他们可以实现ip地址(字符串)和数字之间的互相转换。这样在保存ip地址的时候,可以用4个字节而不是15个字节,可以大大节省空间。(如果存贮ip的数据量很大,推荐用这种方法,如果量不大,几十几百条,还是直接存字符串看着直观)
这个例子第三个特点是利用了数据类型TIMESTAMP。默认情况下,表中的第一个TIMESTAMP列会自动更新为insert和update时的时间戳。(TIMESTAMP值返回后显示为'YYYY-MM-DD HH:MM:SS'格式的字符串,显示宽度固定为19个字符。如果想要获得数字值,应在TIMESTAMP 列添加+0)。在insert子句中,我们之所以没有使用默认值,而是用了now(),是因为如果省略,那么在insert的时候要指明插入的字段名。
那么这个例子是如何运行的呢?和你期望的一样。如果这个ip地址不存在,会增加一条记录,并把hits置为1;如果存在(注意ip是主键),hits会加一,时间戳更新为现在的时间。
使用这个特性来替代INSERT + UPDATE,带来优化依赖于新增行数和数据集的大小。一般情况下会提速30%。性能的提高并不是它带来的唯一好处----更重要的是应用的代码会更简单----减少出错的几率,更加易读。
没有评论:
发表评论