【MySQL】查询百万数据导出处理方法(数据集合统一返回)

小破孩
2025-05-22 / 0 评论 / 10 阅读 / 正在检测是否收录...
    public function getExportList($map)
    {
        // 定义初始分页大小和最小分页大小
        $initialPageSize = 1000;
        $minPageSize = 100;
        $pageSize = $initialPageSize;

        // 计算可用内存(保留15%缓冲)
        $memoryLimit = (int) ini_get('memory_limit') * 0.85;
        $lastId = 0;
        $allData = [];
        $hasMoreData = true;

        // 用于动态调整分页大小的变量
        $lastBatchMemoryUsage = 0;
        $avgRecordSize = 0;

        while ($hasMoreData) {
            // 动态调整分页大小
            if ($lastBatchMemoryUsage > 0 && $avgRecordSize > 0) {
                $currentMemory = memory_get_usage(true) / (1024 * 1024);
                $availableMemory = $memoryLimit - $currentMemory;

                // 基于剩余内存和记录大小计算安全分页大小
                $safePageSize = max(
                    $minPageSize,
                    min(
                        $initialPageSize,
                        (int)($availableMemory / ($avgRecordSize * 1.5))  // 1.5倍安全系数
                    )
                );

                $pageSize = ($safePageSize < $pageSize) ? $safePageSize : $pageSize;
            }

            // 执行分页查询
            $list = self::where($map)
                ->withoutField(['z_create_time', 'z_update_time'])
                ->where('z_id', '>', $lastId)
                ->order('z_id', 'asc')
                ->limit($pageSize)
                ->select();

            if ($list->isEmpty()) {
                break;
            }

            $listData = $list->toArray();
            $batchCount = count($listData);

            // 计算当前批次内存占用
            $batchMemory = memory_get_usage(true);
            foreach ($listData as $record) {
                $allData[] = $record;  // 直接添加减少内存操作
            }
            $batchMemory = (memory_get_usage(true) - $batchMemory) / (1024 * 1024);

            // 更新内存跟踪指标
            if ($batchCount > 0) {
                $currentAvg = $batchMemory / $batchCount;
                $avgRecordSize = ($avgRecordSize > 0)
                    ? ($avgRecordSize * 0.7 + $currentAvg * 0.3)  // 平滑平均
                    : $currentAvg;
                $lastBatchMemoryUsage = $batchMemory;
            }

            // 更新迭代变量
            $hasMoreData = ($batchCount === $pageSize);
            if ($hasMoreData) {
                $lastRecord = end($listData);
                $lastId = (int)$lastRecord['z_id'];
                reset($listData);  // 重置数组指针
            }

            // 资源清理
            unset($list, $listData);
            if (gc_enabled()) {
                gc_collect_cycles();
            }
        }

        return $allData;
    }
    //导出14730条数据,需要34.05秒,字段有50个,全是非空状态,字段数量会影响响应时间,一般导出起飞无压力



        public function getExportList($map)
    {
        $pageSize = 1000;
        $lastId = 0;
        $allData = [];

        while (true) {
            // 查询当前批次
            $list = self::where($map)
                ->withoutField(['z_create_time', 'z_update_time'])
                ->where('z_id', '>', $lastId)
                ->order('z_id', 'asc')
                ->limit($pageSize)
                ->select();

            // 无数据时终止循环
            if ($list->isEmpty()) {
                break;
            }

            $batch = $list->toArray();
            $batchSize = count($batch);

            // 直接追加数据(避免array_merge内存峰值)
            foreach ($batch as $record) {
                $allData[] = $record;
            }

            // 到达数据末尾
            if ($batchSize < $pageSize) {
                break;
            }

            // 更新最后ID
            $lastId = (int)end($batch)['z_id'];

            // 资源清理
            unset($list, $batch);
            if ($batchSize >= 500) { // 仅在大批次后回收
                gc_collect_cycles();
            }
        }

        return $allData;
    }

    //这个是34.59秒。其他有很多方法,正在尝试30秒内
1

评论 (0)

取消