这次操作,起因是需要获取用户来源及用户性别,而用户的性别信息在第三方授权的中有,存为JSON格式,

不想用php去解析获取,所以试试mysql操作

如果你有更好的解决方案,请留言告诉我!

情景简化

表结构

记录用户授权信息,有微博、QQ、微信,个人信息存为user_info

  • user_platform

    • weibo_id,qq_id,weixin_id,user_info,uid,user_platform_id

性别格式

  • 微博 【gender】('m' =>男,'f' => 女,'n' => 未知)
  • QQ 【gender】 ('男' ,'女' )
  • 微信 【sex】(1 =>男,2 => 女)

附加条件

  • 数据量近百万行,处理不能太耗时


用户来源

先来个简单的,因为授权账户不是和用户一一对应,所以就是判断相关第三方id不为空则为对应用户来源,没有涉及绑定所以第三方信息实际唯一(表设计不是很合理,这个略过)

SELECT IF((ISNULL(weixin_id) || weixin_id != '', IF((ISNULL(weibo_id) || weibo_id != '', IF((ISNULL(qq_id) || qq_id != '', '手机', 'QQ'), '微博'), '微信') AS user_source, uid
FROM user_platform
WHERE uid != 0

其中 ISNULL(weixin_id) || weixin_id != '' 用来判断null和空字符串两种情况 也可以用 ISNULL(weixin_id) || LENGTH(TRIM(weixin_id)) < 1

性别获取

  • 分两类(gender,sex)去截取性别,
  • 然后放到临时表中,处理为统一格式的sex(1=>男,2=>女,0=>未知)
  • 在用户表中加一列sex并利用临时表更新

字符替换判断

使用mysql函数

  • locate
  • mid

以微信为例,判断是否包含性别

SELECT locate('sex":', user_info, 50) AS is_sex
FROM user_platform
WHERE user_info != ''
HAVING is_sex != 0

然后截取性别,开始用

SELECT locate('sex":', user_info, 50) AS is_sex, mid(user_info, locate('sex":', user_info, 50) + 5, 1) AS sex
FROM user_platform
WHERE user_info != ''
HAVING is_sex != 0

发现特变慢,而且locate一样的判断执行两次,不如换做一次

SELECT mid(user_info, is_sex + 5, 1) AS sex, uid
FROM user_platform p, (SELECT locate('sex":', user_info, 50) AS is_sex, user_platform_id
FROM user_platform
WHERE user_info != ''
AND uid != 0
HAVING is_sex != 0
) t
WHERE t.user_platform_id = p.user_platform_id
GROUP BY uid

既然判断index,那如果先知道从哪开始判断,那就先获取最小位置,再利用locate第三个参数pos加快查找

SELECT MIN(is_sex)
FROM (SELECT locate('sex":', user_info) AS is_sex
FROM user_platform
WHERE user_info != '' HAVING is_sex != 0
) t

获取到最小位置为:57,那就 locate('sex":', user_info,55) ,其实可以用57,保险起见小点啦

效率提升,主要时间上 (本地PC测试): 10.17 sec 》》》7.36 sec

然后插入到临时表,mysql不能直接select into,所以先创建表载insert into

CREATE TABLE user_sex (
uid int(11) NOT NULL,
sex char(1) NOT NULL,
PRIMARY KEY (uid)
)ENGINE = InnoDB DEFAULT CHARSET = `utf8`; INSERT INTO user_sex
(uid, sex)
SELECT uid, sex
FROM (SELECT mid(user_info, is_sex + 5, 1) AS sex, uid
FROM user_platform p, (SELECT locate('sex":', user_info, 55) AS is_sex, user_platform_id
FROM user_platform
WHERE user_info != ''
AND uid != 0
HAVING is_sex != 0
) t
WHERE t.user_platform_id = p.user_platform_id GROUP BY uid
) tmp

微博和QQ的相同处理,只不过判断的是gender

最后需要处理的是sex字段的统一,用replace搞定

UPDATE user_sex
SET sex = replace(sex, '男', 1);
UPDATE user_sex
SET sex = replace(sex, '女', 2);
UPDATE user_sex
SET sex = replace(sex, 'm', 1);
UPDATE user_sex
SET sex = replace(sex, 'f', 2);
UPDATE user_sex
SET sex = replace(sex, '"', 0);
# 最后一个是发现`gender:""`情况

最后的最后,把临时表删了吧

DROP TABLE user_sex

到这里,可优化的部分还是有的,根据业务,还可以加一些判断减少待处理数据,比方说 uid为0:非注册用户 等等

总结一下,除了在添加user表sex列会锁表比较长时间,

最后的用临时表更新和其余查询操作的锁表时间几乎微乎其微,

把统一操作放临时表也可以避免查询操作等待的时间,

优化无非就是做了大化小的工作。

另外备注下 mysql的sql文件注释符"--"错了,需要一个空格,应该是"-- ".

如果想发现更多,请使用mysql slow query log

慢查询设置

set GLOBAL long_query_time=1
set GLOBAL log_slow_queries=ON
show variables like '%slow%'
show variables like '%long_query%'

本文链接 : http://blog.newbmiao.com/2015/09/25/remember-once-mysql-optimize-operations.html

记一次mysql优化操作的更多相关文章

  1. 记一次 mysql 启动没反应

    记一次 mysql 启动没反应 ,重启linux又可以启动 vim /var/log/mysqld.log 2018-02-04 13:22:49 28507 [ERROR] InnoDB: Cann ...

  2. 记一次MySQL表分区操作

    最近一次日常迭代中,业务线需要对一张大表进行联合查询,查询性能可想而知,测试过程中服务接口直接响应超时,导致服务不可用,最后临时对该表进行分区操作,暂时缓解性能问题.由于是第一次操作表分区,姑且记录一 ...

  3. 记一次mysql数据库被勒索(中)

    背景在上一篇文章里面已经提过了. 现在面临的问题是nextcloud没有mysql数据库,用不起来了. 因为文件没丢,一种方法是启动新的mysql数据库,把文件重新提交一次. 为了程序员的面子,没有选 ...

  4. 记一次mysql数据库被勒索(下)

    背景: nextcloud的mysql数据库被黑,删库勒索.参考:记一次mysql数据库被勒索(上) mysql数据库恢复成功,nextcloud还是无法连接.参考:记一次mysql数据库被勒索(中) ...

  5. 记一次mysql事务未提交导致锁未释放的问题

    记一次mysql事务未提交导致锁未释放的问题 ## 查看未提交的事务(3秒内未操作的事务) SELECT p.ID AS conn_id, P.USER AS login_user, P.HOST A ...

  6. 【夯实Mysql基础】记一次mysql语句的优化过程

    1. [事件起因] 今天在做项目的时候,发现提供给客户端的接口时间很慢,达到了2秒多,我第一时间,抓了接口,看了运行的sql,发现就是 2个sql慢,分别占了1秒多. 一个sql是 链接了5个表同时使 ...

  7. 记一次MYSQL更新优化

    引言 今天(August 5, 2015 5:34 PM)在给数据库中一张表的结构做一次调整,添加了几个字段,后面对之前的数据进行刷新,刷新的内容是:对其中的一个已有字段url进行匹配,然后更新新加的 ...

  8. 记一次mysql故障恢复

    事情要从俩月前的一个坑说起,一台新的测试服务器,新项目一元夺宝用的. 配置aws上的一台云主机,系统盘8G,一块300G的云硬盘. 拿到机器后,另一运维小哥安装php,nginx,mysql等软件. ...

  9. 记一次MySql入库后,文本出现乱码的问题

    最近采用ADO.NET开发了一个工具,解析了一条如下的日志并入库(MySql) -- :: [INFO] roleName=♣丶伊诺,orderId=,price= 发现入库后的roleName中的♣ ...

随机推荐

  1. I.MX6 U-boot imxotp MAC address 写入

    /***************************************************************************** * I.MX6 U-boot imxotp ...

  2. 理解Objective-C Runtime(三)消息转发机制

    消息转发机制概述 上一篇博客消息传递机制中讲解了Objective-C中对象的「消息传递机制」.本文需要讲解另外一个重要问题:当对象受到无法处理的消息之后会发生什么情况? 显然,若想令类能理解某条消息 ...

  3. 「LuoguP1145」 约瑟夫(打表

    Description n 个人站成一圈,从某个人开始数数,每次数到 m 的人就被杀掉,然后下一个人重新开始数,直到最后只剩一个人.现在有一圈人, k 个好人站在一起, k 个坏人站在一起.从第一个好 ...

  4. linux--安装phpcurl扩展

    在UBUNTU中直接用APT包管理工具安装: apt-get install curl libcurl3 libcurl3-dev php5-curl 安装好后重启Apache服务器就行了,如果还是不 ...

  5. IOCP编程小结(上)

    前段时间接手了一个网络游戏前端连接服务器的开发工作,由于服务器需要在windows平台上部署,并且需要处理大量的客户端连接,因此采用IOCP来做为服务器端的编程模型就成了不二选择.虽然我对服务器开发并 ...

  6. 超实用的JavaScript技巧及最佳实践给

    1.数组创建一个随机项 var items = [12,548,'a',2,5478,'foo',8852,,'Doe',2145,119]; var randomItem = items[Math. ...

  7. codeforces 724C

    在一个nxm的镜面二维空间内,向(1,1)发射一条射线,来回反射,当遇到四个角之一时光线消失. 给K个点,问K个点第一次被射中是什么时候(v = sqrt(2)) 解:注意到只有 2*(n+m)个对角 ...

  8. 设计模式——模板模式(Template Pattern)

    在读Spring源码的时候,发现Spring代码中运用了大量的模板模式,比如根据文件系统目录加载配置文件(FileSystemXmlApplicationContext),类路径加载配置文件(Clas ...

  9. android的logcat的message有字符长度的限制,超过将直接截断

    http://blog.csdn.net/qidizi/article/details/47291803 今天想在logcat中输出足够多的调试信息时,发现从logcat中返回的信息中明显少了后面一节 ...

  10. 深度 Mybatis 3 源码分析(一)SqlSessionFactoryBuilder源码分析

    MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java ...