php mysql代码问题,这段代码中step和nums的疑问怎么解决?

以下是完整的示例代码,其中代码中的step和nums有个疑问,假设总记录是从数据表查询的结果,该如何分次数?

下面代码中,nums以及step都是固定值,假设查询总记录是1563000,每次取1000或2000或以上,应该怎么计算step次数?

还是说我理解错误了?请各位指教,谢谢。


set_time_limit(0);
ini_set('memory_limit', '128M');
 
$fileName = date('YmdHis', time());
header('Content-Type: application/vnd.ms-execl');
header('Content-Disposition: attachment;filename="' . $fileName . '.csv"');
 
$begin = microtime(true);
 
$fp = fopen('php://output', 'a');
 
$db = new mysqli('127.0.0.1', 'root', '', 'test');
 
if($db->connect_error) {
    die('connect error');
}
 
$step = 100;
$nums = 10000;
 
$title = array('ID', '用户名', '用户年龄', '用户描述', '用户手机', '用户QQ', '用户邮箱', '用户地址');
foreach($title as $key => $item) {
    $title[$key] = iconv('UTF-8', 'GBK', $item);
}

fputcsv($fp, $title);
 
for($s = 1; $s <= $step; ++$s) {
    $start = ($s - 1) * $nums;
    $result = $db->query("SELECT * FROM tb_users ORDER BY id LIMIT {$start},{$nums}");
    
    if($result) {
        while($row = $result->fetch_assoc()) {
            foreach($row as $key => $item) {
                $row[$key] = iconv('UTF-8', 'GBK', $item);
            }
            fputcsv($fp, $row);
        }
        $result->free();
        
        ob_flush();
        flush();
    }
}
 
$end = microtime(true);
echo '用时:', $end - $begin;

引用new bing部分回答作答:
在这段代码中,$step和$nums都是用于分批次查询数据的参数。

其中,$step表示需要查询的总次数,$nums表示每次查询的记录数。在这段代码中,$step的值为100,$nums的值为10000,因此每次查询10000条记录,总共需要查询100次。

如果总记录数为1563000,那么可以通过如下代码计算出需要查询的总次数:

$total = 1563000;
$nums = 10000;
$step = ceil($total / $nums);

这里使用了PHP的内置函数ceil(),它可以对浮点数进行上取整,这样就可以得到需要查询的总次数。

这里的查询语句使用了LIMIT关键字,它可以控制查询的起始位置和返回的记录数。具体来说,LIMIT 0,10表示从第0条记录开始查询,查询10条记录。因此,我们可以通过修改起始位置和返回的记录数来实现分批次查询数据。

你的理解是正确的,在分步导出大量数据时,step和nums的值应该根据总数据量动态计算。

一个推荐的算法是:

  1. 查询总记录数total
  2. 设置单步导出最大记录数max,例如2000或5000,根据服务器性能决定
  3. 计算总步数step_total = ceil(total/max),向上取整
  4. 循环step_total次:
    • 从第(step-1)*max条记录开始
    • 查询本步需要导出的记录数nums = min(max, total - (step-1)*max)
    • 导出nums条记录

代码实现如下:



php
 $total = $db->query('SELECT COUNT(*) AS total FROM tb_users')->fetch_object()->total;
 $max = 2000;  // 单步最大导出记录数 
 $step_total = ceil($total/$max);
 
 for($step=1; $step<=$step_total; ++$step) {
     $start = ($step-1) * $max;
     $nums = min($max, $total - ($step-1)*$max);
     $result = $db->query("SELECT * FROM tb_users ORDER BY id LIMIT {$start},{$nums}");
     // ... 导出 $nums 条记录
 }

这样,step和nums的值会根据总记录数动态变化,可有效地分批导出大量数据,而不会造成内存溢出。

另外,在导出过程中,记得定期flush缓冲和ob_flush,防止缓冲区过大导致脚本超时或内存溢出。

希望这个解释和示例代码能帮助你理解分批导出数据的算法。有任何其他问题,欢迎在评论中提出。

引用chatGPT作答,在这段代码中,$step是用来表示总共查询的次数的,而$nums则表示每次查询的记录数。如果总记录数为1563000,则可以通过以下方式计算需要查询的次数:

$step = ceil(1563000 / $nums);

其中,ceil()函数用来向上取整,以保证可以查询到所有的记录。在代码中,使用for循环来执行每次查询,通过$start变量来表示每次查询的起始位置,以便分批次查询数据表中的记录。每次查询都会将查询结果转换为CSV格式,并通过fputcsv()函数写入到输出流中,从而实现将查询结果导出到CSV文件的功能。最后,代码输出了查询的用时。

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 以下回答来自chatgpt:

    针对该问题,您可以采取如下步骤实现分批查询:

    1. 确定每一次查询的数量

    根据题目要求,每次取1000条或2000条或更多,可以先设定一个变量 $batch,表示每一次查询的数量。根据具体情况,给 $batch 赋值即可。

    $batch = 2000; // 每次查询2000条记录
    
    1. 计算分批次数

    因为要查询的总记录数为1563000,需要分批进行查询,为了避免查询的过程中占用太多内存,需要对查询进行分批。可以使用 $batch 变量来计算需要分批的次数。

    $totalNums = 1563000; // 总记录数
    $step = ceil($totalNums / $batch); // 计算分批次数,向上取整
    
    1. 循环查询分批数据

    通过循环执行 SQL 语句来逐批查询数据。每一批查询时,需要计算出当前查询的起始位置 $offset 和查询记录的数量 $limit

    for ($i=0; $i<$step; $i++) {
        $offset = $i * $batch; // 计算当前查询的起始位置
        $limit = $batch; // 查询记录的数量
        $sql = "SELECT * FROM table_name LIMIT $offset,$limit";
        // 执行 SQL 语句,获取查询结果
        // ...
    }
    

    其中,LIMIT $offset,$limit 表示从 $offset 开始取 $limit 条记录。

    综上所述,您可以使用如下代码实现分批查询:

    // 确定每一次查询的数量
    $batch = 2000;
    // 计算分批次数
    $totalNums = 1563000;
    $step = ceil($totalNums / $batch);
    
    // 循环查询分批数据
    for ($i=0; $i<$step; $i++) {
        $offset = $i * $batch; // 计算当前查询的起始位置
        $limit = $batch; // 查询记录的数量
        $sql = "SELECT * FROM table_name LIMIT $offset,$limit";
        // 执行 SQL 语句,获取查询结果
        // ...
    }
    

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^