这次操作,起因是需要获取用户来源及用户性别,而用户的性别信息在第三方授权的中有,存为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. 「LuoguP2014」 选课

    Description 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学 ...

  2. codevs3955最长严格上升子序列

    传送门  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond   题目描述 Description 给一个数组a1, a2 ... an,找到最长的上升降子序列 ...

  3. 我自己常用的Watir自动化测试结果报表

    特别声明:该报表框架不是我搭建的.

  4. U3D Navigation

    让我们来一起粗步认识一下NavMesh的简单使用 首先我们建立一个新场景,在新场景我们创建 一个地形或者创建一个Plane, 然后在其上面用Cube或者其它的建立一些障碍物 再创建自己需要为其设置自动 ...

  5. 【转】implements百科

    implements是一个类,实现一个接口用的关键字,它是用来实现接口中定义的抽象方法.实现一个接口,必须实现接口中的所有方法.   中文名 实现 外文名 implements 意    思 类实现一 ...

  6. perceptron and ANN

    %% Perceptron Regression close all clear %%load data x = load('ex4x.dat'); y = load('ex4y.dat'); x=o ...

  7. Codeforces - 474D - Flowers - 构造 - 简单dp

    https://codeforces.com/problemset/problem/474/D 这道题挺好的,思路是这样. 我们要找一个01串,其中0的段要被划分为若干个连续k的0. 我们设想一个长度 ...

  8. bzoj3343 教主的魔法【分块入门】By cellur925

    题意:维护一个数列,给出维护区间加法,询问区间内大于等于某个值的元素个数. 算法:分块.因为本题第二问显然可以用二分的思想,但是这貌似并不符合区间可加性,线段树好像就不好用了呢.所以本蒟蒻学习了分块. ...

  9. Comet OJ - Contest #4--前缀和

    原题:Comet OJ - Contest #4-B https://www.cometoj.com/contest/39/problem/B?problem_id=1577传送门 一开始就想着暴力打 ...

  10. jQuery笔记之工具方法—Ajax 优化回调地狱

    在上一篇文我们说到了回调地狱不好的地方,今天我们看看怎么来优化它,让它可以运用到实际开发中. 什么是回调地狱?回调地狱就是一个函数里面嵌套了所有功能函数,然后缩略图形成一个三角形. 这样的代码可复用性 ...