2014-03-31 96 views
2

rows.Scan()的性能,我有一個返回幾千行,只有兩列的非常簡單的查詢:提高圍棋

SELECT "id", "value" FROM "table" LIMIT 10000; 

發行sql.Query()後,我遍歷結果有以下設置代碼:

data := map[uint8]string{} 

for rows.Next() { 
    var (
     id  uint8 
     value string 
    ) 

    if error := rows.Scan(&id, &value); error == nil { 
     data[id] = value 
    } 
} 

如果我直接在數據庫上運行完全相同的查詢,我得到的所有結果幾毫秒之內復出,但Go代碼需要更長的時間完成,有時10秒左右

我開始註釋代碼的幾個部分,它似乎是rows.Scan()是罪魁禍首。

掃描將當前行中的列複製到dest所指向的值 處。

如果參數的類型爲* []字節,則掃描在該參數中保存對應數據的副本 。該副本由主叫方擁有,可以修改並保留無限期地 。可以通過使用類型* RawBytes的 參數來避免該副本;請參閱RawBytes 的文檔以瞭解其使用限制。如果參數的類型爲* interface {},則 掃描會複製由底層驅動程序提供的值,而不會使用 轉換。如果該值是[]字節類型,則進行復制並且調用者擁有結果。

任何能想到的任何速度的提高,如果我使用*[]byte*RawBytes*interface{}呢?

看着the code,它看起來像convertAssign() function做了很多東西,這是不需要這個特定的查詢。所以我的問題是:我怎樣才能使Scan過程更快?

我想過超載期望預定類型的功能,但是這是不可能去...

任何想法?

+1

當您嘗試使用'* [] byte','* RawBytes'和'* interface {}'時發生了什麼? – peterSO

+0

@peterSO:當我讀取'* RawBytes'的文檔和數據時,只要您調用'rows.Next()'就會消失。我還沒有嘗試過其他兩個,我只是問它是否會對任何事情有所幫助。如果你看看'convertAssign'源代碼(在答案中鏈接),'uint8'類型仍然需要進行思考。 –

+1

您是否嘗試使用分析器來幫助縮小範圍? –

回答

2

是的,你可以使用RawBytes代替和rows.Scan()將避免內存分配/複製

關於convertAssign()功能 - 是的,它在Go 1.2, 不是最優的,但他們做了130顯著的改進:
- http://code.google.com/p/go/issues/detail?id=7086
https://gist.github.com/yvasiyarov/9911956

- - 爲sync.Pool

RawBytes使用的一些示例鎖定落實少

此代碼從MySQL表中讀取數據,進行一些處理並將其寫入CSV文件。 昨晚需要1分24秒才能生成4GB的CSV數據(約3000萬行)

所以我很確定外面的代碼有什麼問題:rows.Scan()甚至可能更糟糕的用法不能給你10秒延遲。

+0

原因是冷數據庫和繁忙的磁盤,感謝回答。 –