V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
alwayshere
V2EX  ›  程序员

PHP 脚本要对 600 万行的 mysql 进行一次批处理操作,怎样才能用多个进程达到最快执行?

  •  
  •   alwayshere · 2018-08-06 14:10:34 +08:00 · 4980 次点击
    这是一个创建于 2300 天前的主题,其中的信息可能已经有所发展或是发生改变。

    要扫描一次全表,php 对每一行都要批处理一次,如果单个 php 进程把 600 万行载入内存扫描一次全表处理实在太慢,想用多个 php 进程来扫描表:

    1. 想用多个 php 进程从 MySQL 中随机取出一些行出来,因为 primary id 不连续,但用 MySQL 的 ORDER BY RAND()慢的令人发指

    2. 想快一点也只能用两个 php 进程,一个 ORDER BY id ASC 顺序执行,一个 ORDERY BY id DESC 倒序执行,但两个进程还是太慢

    估计表述得不太明白,反正就是怎样能将 mysql 快速截取成一段一段的行,让多个 php 进程去执行?

    33 条回复    2018-08-07 14:55:33 +08:00
    Sornets
        1
    Sornets  
       2018-08-06 14:14:29 +08:00
    一个思路:
    记录 id 取余,比如十个进程,就对 10 取余,根据余数查找对应 id,proc_id = rec_id % 10,
    z550665887
        2
    z550665887  
       2018-08-06 14:18:04 +08:00
    limit ?
    582033
        3
    582033  
       2018-08-06 14:25:58 +08:00
    分页
    Rekkles
        4
    Rekkles  
       2018-08-06 14:29:36 +08:00
    PHP 哪有什么多进程 pthread 性能不会有太大的提高 这种东西如果打算用 PHP 做,mysql 和内存 能扛就能做,一次取 1k 条数据(内存够就多取点),处理 ,update,循环
    lihongjie0209
        5
    lihongjie0209  
       2018-08-06 14:30:57 +08:00
    生产者消费者喽
    widdy
        6
    widdy  
       2018-08-06 14:34:20 +08:00   ❤️ 2
    有这扯淡时间,一个脚本 600w 行早跑完了,为啥不一次取个 1w 条。
    nsxuan
        7
    nsxuan  
       2018-08-06 15:00:43 +08:00
    关键是要开启事务
    colincat
        8
    colincat  
       2018-08-06 15:46:00 +08:00
    @widdy 说的没毛病
    newtype0092
        9
    newtype0092  
       2018-08-06 15:54:15 +08:00
    @widdy 那就来讨论下 6 亿条怎么做嘛,让这个淡扯的有点意义~
    tanszhe
        10
    tanszhe  
       2018-08-06 15:58:00 +08:00
    这种简单到爆的问题 就不要来问了
    mumbler
        11
    mumbler  
       2018-08-06 16:02:37 +08:00
    order by id limit 1,10000
    order by id limit 10001,10000
    order by id limit 20001,10000
    order by id limit 30001,10000
    这样就可以一万一万读了,和分页一样
    widdy
        12
    widdy  
       2018-08-06 16:03:09 +08:00
    @newtype0092 , 真这么大,时间来最清晰,php xxoo.php 2017-01 , php xxoo.php 2017-02 ...
    ps1aniuge
        13
    ps1aniuge  
       2018-08-06 16:06:41 +08:00
    一个进程不行,就多个进程。多个进程不行就 n 机子分布。
    这里面要有一个队列,分发任务或表 id。根据实际情况,一次分发一百,一千,一万。
    vacker
        14
    vacker  
       2018-08-06 16:10:00 +08:00 via Android
    用队列,随便多少条都可以
    GGGG430
        15
    GGGG430  
       2018-08-06 16:10:42 +08:00 via iPhone
    pcntl,我上周才刚用过,你把行数除以进程数,然后把各个起始 id 传给各个子进程,快的一比
    yuanfnadi
        16
    yuanfnadi  
       2018-08-06 16:11:33 +08:00
    select * from xxx where id > 0 limit 1000
    然后取最后一个 ID 为 1022
    select * from xxx where id > 1022 limit 1000
    想开几个线程都可以。
    GGGG430
        17
    GGGG430  
       2018-08-06 16:13:12 +08:00 via iPhone
    不要排序,各个进程处理各自起始 id 部门数据,然后各个进程都每次取 100 条数据作为一个事物提交,但注意 mysql 连接数和执行脚本机器的负载
    dobelee
        18
    dobelee  
       2018-08-06 16:16:20 +08:00 via Android
    600w。。随便跑跑就行,等你写好算法逻辑,10 遍都跑完了。
    jswh
        19
    jswh  
       2018-08-06 16:32:51 +08:00
    记得别用对象,用数组就行
    InternetExplorer
        20
    InternetExplorer  
       2018-08-06 16:38:31 +08:00
    能不能直接用 sql 处理?
    xmadi
        21
    xmadi  
       2018-08-06 18:11:39 +08:00 via iPhone
    用 limit 效率很低 可以直接先人工查询最大的 id 和最小的 id 然后以十万个 id 间隔分组 很粗糙肯定不均匀但是没有影响 开进程池 每个进程用 where 筛选分组数据进行处理
    bugsnail
        22
    bugsnail  
       2018-08-06 19:39:48 +08:00 via iPhone
    @mumbler https://oyifan.com/2016/03/23/offsetSlow/

    了解一下,limit 是会越来越慢的
    singer
        23
    singer  
       2018-08-06 19:47:37 +08:00 via iPhone
    id 放到 redis 的 list,然后多进程拉起来就好了个
    xschaoya
        24
    xschaoya  
       2018-08-06 21:41:24 +08:00
    最简单的多进程资源分配啊,简单粗暴的就是主键分段开多进程。高级点的可以用消息队里(生产者消费者类模型)
    GreatHumorist
        25
    GreatHumorist  
       2018-08-06 22:38:01 +08:00 via iPhone
    还是想想直接用 sql 吧,php 弄很麻烦,上周末弄过一个三百万行的匹配,php 遍历到十万左右就很慢了。最后直接用 sql,贼快,加起来不超过 10 分钟
    yangqi
        26
    yangqi  
       2018-08-06 22:41:32 +08:00
    多复杂的处理不能在 mysql 里面完成?
    beastk
        27
    beastk  
       2018-08-06 22:45:55 +08:00 via iPhone
    要不就用 php 执行个 go 或者 python,分分钟给你跑完
    jsjscool
        28
    jsjscool  
       2018-08-06 23:46:11 +08:00
    使用进程间通信也是几句代码的事情。和语言无关,通信的方式无非就是信号量,消息队列,管道这几种,都是操作系统提供的。选择一种自己能理解的方式就行了,代码都贴给你
    http://blog.it2048.cn/article-php-thread/

    PS:600 万行这么少的数据,几句代码就能搞定,用啥多线程。 就算用了多线程速度也提升不了多少,MySQL 的硬盘 IO 会是瓶颈。比如每秒 40M,你写入数据的极限也差不多是 40M/s。
    wizardoz
        29
    wizardoz  
       2018-08-07 10:30:33 +08:00
    为啥要用 php 处理?不是放进数据库用 SQL 处理最快吗?
    allgy
        30
    allgy  
       2018-08-07 10:54:46 +08:00
    @jsjscool @alwayshere php 的线程就是个废物不建议使用,大数据量用存储过程就行
    slince
        31
    slince  
       2018-08-07 12:33:32 +08:00
    这种问题应该要你们的 dba,为啥要程序员自己写脚本去解决
    batter
        32
    batter  
       2018-08-07 14:30:58 +08:00
    说 limit 的,你是来搞笑的么,,,,,对于超大数据来说,limit 效率非常的低,既然按照 id 处理,按照 id>$id 应该会好点吧
    abccccabc
        33
    abccccabc  
       2018-08-07 14:55:33 +08:00
    楼主,你还没有执行吗?队列呀,14 楼,23 楼都说了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2675 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 12:15 · PVG 20:15 · LAX 04:15 · JFK 07:15
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.