因公司需要,最近上了一个邀请好友,获得奖金的功能。上了一段时间,为了吸引客户,刷羊毛现象严重.要重新从数据里边封禁账号.二次处理数据的坑;
语言:php 框架tp5
实际需求 ①:ipv4 去前三位ip一致,保留三个账号,其余封掉
②:手机号前六位一致,保留十个账号,其余封掉
③:手机号前七位一致,保留三个账号,其余封掉
④:手机号前八位一致,保留一个账号,其余封掉
⑤:以上规则,都是封禁每个代理下的
刚开始的解决思路是
查询出所有的不同的IP,手机号,查出所有的代理,再foreach查询去处理
//查询不同代理
$source=Db::name('user')->field('source')->distinct(true)->select();
//查询不同ip
$ip=Db::name('user')->field('ip')->distinct(true)->select();
//循环ip
foreach($ip as $k=>$v){
//循环代理
foreach($source as $k2=>$v2){
//分解ip
$arrIp = explode('.',$v['ip']);
$ip=$arrIp[0].'.'.$arrIp['1'].'.'.$arrIp['2'];
//查询条件
$map['source']=$v2['source'];
$map['ip']=['like','%'.$ip];
//查出总数
$count=Db::name('user')->field('id')->where($map)->count();
if($count>3){
//变为应封禁状态
Db::name('user')->where($map)->update(['statusBan'=>'2']);
}
}
}
可能很多朋友都跟我一个想法,而且这是一个定时脚本,暂时忽略了注册时间问题
这个效率可想而知,基本都会502
新的解决方案是查库,在mysql处理好这一切
首先,查出前三位ip
//先查出 ip前三段
SELECT
substring_index(registerIP, '.', 3)
FROM
ban;
//解释一下sql
EXPLAIN SELECT
substring_index(registerIP, '.', 3)
FROM
ban;
//type 只达到了index 使用了索引 2万条大概需要4s
SELECT
registerIP
FROM
ban;
//type 只达到了index 使用了索引 2万条大概需要1.6s
//这个mysql函数速度还是可以用的 substring_index 这里不过多解释 不知道的可以搜一下
//根据ip 分组 得到ip出现的次数
SELECT
substring_index(registerIP, '.', 3) AS ip,
count(registerIP) AS count
FROM
ban
GROUP BY
substring_index(registerIP, '.', 3);
//也是两秒左右
//我们最终是要每个代理下的ip
SELECT
source,//上级
substring_index(registerIP, '.', 3) AS ip,//切割ip
COUNT(registerIP) AS count//得到数量
FROM
user
GROUP BY
substring_index(registerIP, '.', 3),//根据切割的ip分组
source
HAVING
count > 3 //出现次数大于三次
ORDER BY
count DESC
//1.17s结束查询 每个代理下面的ip 和出现的次数都得到了 省去了两步for循环
php代码:
//查出分组
$arrIp = Db::query("SELECT source,substring_index(registerIP, '.', 3) AS ip, COUNT(registerIP) AS count FROM user WHERE `status` <> '3' and `status` <> '1' and addtime >=:time AND registerIP > 0 GROUP BY substring_index(registerIP, '.', 3), source HAVING count > 3 ORDER BY count DESC", ['time' => $time]);
//习惯过滤一遍
foreach ($iparr as $k => $v) {
if ($v['count'] < 3) {
unset($iparr[$k]);
}
}
//后边省略 .....
手机号如果这样处理的话,也会崩溃
错误的php代码就不展示了
//不过多的分析了
SELECT source,//上级
substring(mobile,1,6) AS mobile,//切割手机号 6或者7 8
COUNT(mobile) AS count //得到总数
FROM
user
GROUP BY //分组
substring(mobile,1,6),
source
HAVING
count > 10 //条件
ORDER BY
count DESC
//substring() mysql 内置函数
//两万数据 效率 0.0xx 级
运用 substring,substring_index
这样成功解决了Ip和手机号处理的问题;实际应用中,加上判断注册时间,处理状态,效率更加;php如果处理过多的地sql查询 ,还是mysql处理好
新手上路,多多关照