由于目前仅仅通过mysql来进行数据的存储,要完成复杂的数据统计耗时较长。因此考虑将部分数据导入到redis中,完成数据统计后,再将结果存入mysql。
经查资料,利用管道的方式可以绕开第三方的数据交互过程,数据直接从mysql导入到redis的速度非常快。在笔者的测试环境中,500w级别的数据大概用时40秒(当然了,与mysql的查询耗时有关)。
另外,由于mysql表设计的问题,大部分数据存储在结构相同的不同表中。比如表A存储了用户"启动应用"这个事件数据, 表B存储了用户"打开设置页面"的事件数据, 但是表A和表B的结构都是一样的。 目前在通过mysql来做数据统计时,是按顺序的来进行操作,统计完了A,再统计B。
而在redis中,表A和表B的数据和以放在同一个数据库中,然后利用set之类的容器将各个事件的数据分类存储起来,遍历一次便可以完成所有事件数据的统计。
因此,现在的应用场景为: 批量导出mysql中各个表的相同条件的数据(如同为某一天的数据), 导入redis,最后合并完成统计。具体的导出导入代码如下所示(mysql2redis.sh):
#!/bin/bash
mysql_host=192.168.x.xx
mysql_user=xiaomo
mysql_pwd=xiaomo
database=test_db
tbls_prefix="test_tbl_name_prefix"
#调用shell时,传入的日期参数
cur_dt="$1"
#遍历表,返回表名list
table_list=$(mysql -h$mysql_host -u$mysql_user -p$mysql_pwd $database -A -Bse "show tables")
function gen_sql()
{
src_tbl=$1
mysql2redis="SELECT CONCAT( ‘*10\r\n‘, ‘$‘, LENGTH(redis_cmd), ‘\r\n‘,redis_cmd, ‘\r\n‘, ‘$‘, LENGTH(redis_key), ‘\r\n‘,redis_key, ‘\r\n‘, ‘$‘, LENGTH(hkey1), ‘\r\n‘, hkey1, ‘\r\n‘, ‘$‘, LENGTH(hval1), ‘\r\n‘, hval1, ‘\r\n‘, ‘$‘, LENGTH(hkey2), ‘\r\n‘, hkey2, ‘\r\n‘, ‘$‘, LENGTH(hval2), ‘\r\n‘, hval2, ‘\r\n‘, ‘$‘, LENGTH(hkey3), ‘\r\n‘, hkey3, ‘\r\n‘, ‘$‘, LENGTH(hval3), ‘\r\n‘, hval3, ‘\r\n‘, ‘$‘, LENGTH(hkey4), ‘\r\n‘, hkey4, ‘\r\n‘, ‘$‘, LENGTH(hval4), ‘\r\n‘, hval4, ‘\r‘ ) FROM ( SELECT ‘HMSET‘ AS redis_cmd, uniq_id AS redis_key, ‘f1‘ AS hkey1, f1 AS hval1, ‘f2‘ AS hkey2, f2 AS hval2, ‘f3‘ AS hkey3, f3 AS hval3, ‘f4‘ AS hkey4, f4 AS hval4 FROM $src_tbl WHERE dt=‘$cur_dt‘ ) AS T"
echo "$mysql2redis"
}
prefix_len=$(expr length $tbls_prefix)
for arg in $table_list
do
if [[ "${arg:0:$prefix_len}" == ${tbls_prefix} ]] # 判断表名是否匹配(表名以指定前缀开头)
then
mysql2redisCmd=$(gen_sql $arg)
echo $mysql2redisCmd | mysql -u$mysql_user -p$mysql_pwd -h$mysql_host $database --skip-column-names --raw | redis-cli -n 1 --pipe
fi
done
调用示例: /bin/bash mysql2redis.sh 2014-03-08
另: 可参考redis的resp协议文档 http://redis.io/topics/protocol