cqwcns 发表于 2019-10-3 15:44

PHP写入MYSQL代码性能如何提升

经常需要大量更新数据到MYSQL(根据操作类型决定增改删),动辄数万甚至十几万行,前端POST过来是JSON,为了提高稳定性和避免服务器限制数据大小,前端会将数据分割成1000条每组发到服务器(1000条不到1M)。
问题来了,我写的代码处理这1000条数据竟然要解决20秒,效率很低。我想应该是我写的代码不够科学,请大神抽时间帮忙改改,感谢{:1_893:}{:1_893:}{:1_893:}

<?php
header( "Content-Type: text/html; charset=utf-8" );
//连接数据库
include( "conn.php" );
$arrDiZhi = json_decode( $_POST[ 'arrDaoRuDiZhi' ], true );
$DangQianShiJian = date( "Y-m-d H:i:s" );
//计数变量
$vXinZengT = 0;
$vXinZengF = 0;
$vXiuGaiT = 0;
$vXiuGaiF = 0;
$vShanChuT = 0;
$vShanChuF = 0;
$vLeiXingCuoWu = 0;

foreach ( $arrDiZhi as $arrRow ) {

        $DaoRuCaoZuo = $arrRow[ 'DaoRuCaoZuo' ];
        $WangGeID = $arrRow[ 'WangGeID' ];
        $WangGe = $arrRow[ 'WangGe' ];
        $DiZhiID = $arrRow[ 'DiZhiID' ];
        $PARENTID = $arrRow[ 'PARENTID' ];
        $BenJiMingCheng = $arrRow[ 'BenJiMingCheng' ];
        $DiZhiJiBie = $arrRow[ 'DiZhiJiBie' ];
        $DiZhiQuanCheng = $arrRow[ 'DiZhiQuanCheng' ];
        $ChangJingLeiXing = $arrRow[ 'ChangJingLeiXing' ];
        $DiYuShuXing = $arrRow[ 'DiYuShuXing' ];
        $DiZhi1Ji = $arrRow[ 'DiZhi1Ji' ];
        $DiZhi2Ji = $arrRow[ 'DiZhi2Ji' ];
        $DiZhi3Ji = $arrRow[ 'DiZhi3Ji' ];
        $DiZhi4Ji = $arrRow[ 'DiZhi4Ji' ];
        $DiZhi5Ji = $arrRow[ 'DiZhi5Ji' ];
        $WagnLuoLaiYuan = $arrRow[ 'WagnLuoLaiYuan' ];
        $DiZhiLaiYuan = $arrRow[ 'DiZhiLaiYuan' ];

        if ( $arrRow[ 'DaoRuCaoZuo' ] == 1 ) {

                if ( $result = $mysqli->query( "SELECT id FROM dizhi WHERE DiZhiID='$DiZhiID'" ) ) {
                        $row_cnt = $result->num_rows;
                        $result->close();
                        if ( $row_cnt > 0 ) {
                                //修改

                                if ( $result = $mysqli->query( "UPDATE `dizhi` SET `WangGeID` = '$WangGeID', `WangGe` = '$WangGe',`PARENTID` = '$PARENTID', `BenJiMingCheng` = '$BenJiMingCheng', `DiZhiJiBie` = '$DiZhiJiBie', `DiZhiQuanCheng` = '$DiZhiQuanCheng', `ChangJingLeiXing` = '$ChangJingLeiXing', `DiYuShuXing` = '$DiYuShuXing', `DiZhi1Ji` = '$DiZhi1Ji', `DiZhi2Ji` = '$DiZhi2Ji', `DiZhi3Ji` = '$DiZhi3Ji', `DiZhi4Ji` = '$DiZhi4Ji', `DiZhi5Ji` = '$DiZhi5Ji', `WagnLuoLaiYuan` = '$WagnLuoLaiYuan', `DiZhiLaiYuan` = '$DiZhiLaiYuan' WHERE `DiZhiID` = '$DiZhiID'" ) ) {
                                        if ( $mysqli->affected_rows > 0 ) {
                                                ++$vXiuGaiT;
                                        } else {
                                                ++$vXiuGaiF;
                                        };
                                };
                        } else {
                                //新增
                                $query = "INSERT INTO `dizhi` (`id`, `WangGeID`, `WangGe`, `DiZhiID`, `PARENTID`, `BenJiMingCheng`, `DiZhiJiBie`, `DiZhiQuanCheng`, `ChangJingLeiXing`, `DiYuShuXing`, `DiZhi1Ji`, `DiZhi2Ji`, `DiZhi3Ji`, `DiZhi4Ji`, `DiZhi5Ji`, `WagnLuoLaiYuan`, `DiZhiLaiYuan`, `LuRuShiJian`, `LuRuRen`) VALUES (NULL, '$WangGeID', '$WangGe', '$DiZhiID', '$PARENTID', '$BenJiMingCheng', '$DiZhiJiBie', '$DiZhiQuanCheng','$ChangJingLeiXing', '$DiYuShuXing', '$DiZhi1Ji', '$DiZhi2Ji', '$DiZhi3Ji', '$DiZhi4Ji', '$DiZhi5Ji', '$WagnLuoLaiYuan', '$DiZhiLaiYuan','$DangQianShiJian', '管理员')";

                                $mysqli->query( $query );
                                if ( $mysqli->affected_rows > 0 ) {
                                        ++$vXinZengT;
                                } else {
                                        ++$vXinZengF;
                                };

                        }; //判断结果集是否大于0
                }; //判断是否已存在


        } else if ( $arrRow[ 'DaoRuCaoZuo' ] == 0 ) {
                //删除

                $query = "DELETE FROM dizhi WHERE DiZhiID='$DiZhiID'";
                $mysqli->query( $query );

                if ( $mysqli->affected_rows > 0 ) {
                        ++$vShanChuT;
                } else {
                        ++$vShanChuF;
                };

        } else {
                //操作类型错误
                ++$vLeiXingCuoWu;
        }; //判断操作
}; //循环Row

$mysqli->close();


$arrFanHui = array( $vXinZengT, $vXinZengF, $vXiuGaiT, $vXiuGaiF, $vShanChuT, $vShanChuF, $vLeiXingCuoWu );
echo json_encode( $arrFanHui, JSON_UNESCAPED_UNICODE );

?>

cqwcns 发表于 2019-10-3 16:08

刚刚在网上查了一下,有人说循环太多时建议释放缓冲,不知道怎么弄,请大神指教。

smldhz 发表于 2019-10-3 16:21

本帖最后由 smldhz 于 2019-10-3 16:23 编辑

php+mysql 是同步操作没有并发,是一条一条来执行,效率比较低,看网上讨论一般update的话是一秒钟几十条 符合你的情况。
优化的话,尽量减少查询次数
比如update 原来是
update xx set a='a',b='1111' where c=1;
update xx set a='b',b='2222' where c=2;
update xx set a='c',b='3333' where c=3;
改成
UPDATE xx
    SET a = CASE c
      WHEN 1 THEN 'a'
      WHEN 2 THEN 'b'
      WHEN 3 THEN 'c'
    END,
    b = CASE c
      WHEN 1 THEN '1111'
      WHEN 2 THEN '2222'
      WHEN 3 THEN '3333'
    END
WHERE c IN (1,2,3)
这样一条语句更新多个记录 速度会快非常多(比for循环单条更新快10倍以上)

insert的话 把数据按格式输出到文本 然后用LOAD DATA INFILE会快非常非常非常多(需要pdo方式连接数据库)

或者php就负责接收数据 输出到其他外部程序(脚本)来做并行查询,再返回结果。

加个参考链接
https://stackoverflow.com/questions/3952288/speeding-up-large-numbers-of-mysql-updates-and-inserts

6662680 发表于 2019-10-3 16:30

楼上说的不错,写后端,特别是注重速度的,严禁循环里有对数据库操作,这个被主管看到要挨屌的

namedlxd 发表于 2019-10-3 16:43

批量插入, 不要一条一条插

Rookietp 发表于 2019-10-3 17:36

thinkphp

cqwcns 发表于 2019-10-3 18:21

smldhz 发表于 2019-10-3 16:21
php+mysql 是同步操作没有并发,是一条一条来执行,效率比较低,看网上讨论一般update的话是一秒钟几十条...

谢谢大哥,你的回复对我非常有价值,另外还有一个问题,判断数据是否已存在,如果存在,就UPDATE,否则INSERT。这一点,搞得我全部都SELECT一次通过返回值了判断,这个有改善的空间吗?谢谢

cqwcns 发表于 2019-10-3 18:22

谢谢各位,另外还有一个问题,判断数据是否已存在,如果存在,就UPDATE,否则INSERT。这一点,搞得我全部都SELECT一次通过返回值了判断,这个有改善的空间吗?谢谢

smldhz 发表于 2019-10-3 18:55

cqwcns 发表于 2019-10-3 18:22
谢谢各位,另外还有一个问题,判断数据是否已存在,如果存在,就UPDATE,否则INSERT。这一点,搞得我全部都 ...

REPLACE INTO 啊

cqwcns 发表于 2019-10-3 20:35

smldhz 发表于 2019-10-3 18:55
REPLACE INTO 啊

你好,REPLACE INTO有个问题。
因为前端POST过来的不是全部字段,例如该条记录的创建的时间,是首次创建时在PHP赋值的。
如果用REPLACE INTO,会覆盖掉首次创建时间(我们不希望创建时间被UPDATE)。
对于这种情况,还有什么好方法,感谢。
页: [1] 2
查看完整版本: PHP写入MYSQL代码性能如何提升