首頁  >  問答  >  主體

php查詢回傳資料過大 導入csv檔案很慢

框架用的是ci,資料庫是sqlsrv(sql server 2008),sql查詢回傳的結果集有2萬個數據,我在ci框架裡面執行這個sql語句,網頁一直在轉圈,2萬個資料要轉30秒左右,但我的sql語句在sql server 2008 R2 裡面執行是秒查,在ci裡面用自帶查詢sql執行時間是200毫秒,,表示我的語句不慢。個人覺得應該是回傳數據太多導致慢的,回傳的是2萬條數據,20個欄位左右,,因為我做的是統計,要把數據導出成csv檔,所以數據比較多,這個該怎麼處理?
我的sql 語句是select * from table where create_time between 'xxxx-xx-xx 00:00:00' and 'xxxx-xx-xx 23:59:59'; 是根據時間段來的如果使用者選擇的時間範圍小那資料就少如果範圍大那資料就大數據大的時候就很慢

public function aa(){

$sql ="select * from table where create_time between 'xxxx-xx-xx 00:00:00' and 'xxxx-xx-xx 23:59:59'";
$result=$this->db->query($sql)-result_array();

}
這已經是最簡單的查詢了,sql語句秒查,但是用瀏覽器執行就很慢,
我在瀏覽器裡面執行, 如果查詢結果幾萬條的話瀏覽器就一直轉圈,要等四十多秒,500條足有數據是3、4秒

我在想是不是result_array()這一步 需要循環需要花費太多的時間,本身記錄就有幾萬條,然後還有二十個字段

==============2017-05-16 16:01更新===============
我沒有用ci框架自帶的result_array() ,查看ci框架文檔的時候看到一段話:
經常的,你會需要提供一個資料庫的connection ID 或是一個result ID, connection ID 可以這樣來

$this->db->conn_id;

result ID 可以從查詢傳回的結果物件取得,像這樣:

$query = $this->db->query("SOME QUERY");
$query->result_id;

於是我修改了我的程式碼拿result_id 去循環讀取每筆記錄
$sql ="select xxx";
$query=$this->db->query($sql) ;
//這裡因為我用的是sqlsrv 所以使用的是sqlsrv_fetch_array 來循環讀取每一行
//然後每讀一行就寫如csv檔
while($row=sqlsrv_fetch_array($query ->result_id,SQLSRV_FETCH_ASSOC)){
//這裡是把row 寫入csv檔案的程式碼
}

具體的程式碼就是下面了

$sql="xxx";
$query=$this->db->query($sql);
$filename= "CostDetail.csv";//导出的文件名
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="'.$filename.'"');
header('Cache-Control: max-age=0');

// 打开PHP文件句柄,php://output 表示直接输出到浏览器
$fp = fopen('php://output', 'a');

// 输出Excel列名信息
$head = array(xxx);
foreach ($head as $i => $v) {
    // CSV的Excel支持GBK编码,一定要转换,否则乱码
    $head[$i] = iconv('utf-8', 'gbk', $v);
}

// 将数据通过fputcsv写到文件句柄
fputcsv($fp, $head);

// 计数器
$cnt = 0;
// 从数据库中获取数据,为了节省内存,不要把数据一次性读到内存,从句柄中一行一行读即可
$limit = 5000;

while ($row=sqlsrv_fetch_array($query->result_id,SQLSRV_FETCH_ASSOC)){
    $cnt ++;
    if ($limit == $cnt) { //刷新一下输出buffer,防止由于数据过多造成问题
        ob_flush();
        flush();
        $cnt = 0;
    }
    //这里是把每个字段的编码转成gbk
    $newRow[] = $this->_mb_convert_encoding($row['edis_orgsoid']);
    ....    
    unset($row);
    fputcsv($fp, $newRow);
    unset($newRow);
}

exit;

這樣能匯出檔但是我看了一下19204行的,16列的csv檔3M左右,需要40-45秒的時間才能匯出好,,我想問這時間還能優化的再快點嗎

怪我咯怪我咯2736 天前753

全部回覆(2)我來回復

  • 大家讲道理

    大家讲道理2017-05-17 09:57:57

    這種要把所有資料匯出到excel是這樣的。資料要查出來才能寫入excel,這種我一般用後台程序導出之後發郵箱

    回覆
    0
  • 给我你的怀抱

    给我你的怀抱2017-05-17 09:57:57

    提供一點思路:

    • 前端應該有幾個時間範圍選擇,後端根據這些時間範圍定時跑任務去數據庫獲取放在伺服器上作為靜態文件並且綁定一個timemodified字段;

    • 每次該表增加、刪除或修改後也要觸發更新定時任務;也可以在每天客戶量比較少的時段例如夜裡做定時任務更新;

    • 每次導出的時候,透過比對timemodified,如果相同則可以將先前導出的靜態檔案提前拿過來,如果不等則需要現場更新,不過這種情況應該比較少;

    這樣去資料庫取資料的操作不會影響客戶的使用,希望能幫助你

    回覆
    0
  • 取消回覆