在Go中提高rows.Scan()的性能

时间:2014-03-31 22:26:26

标签: performance sqlite go database-performance

我有一个非常简单的查询,返回几千行,只有两列:

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。

     

如果参数的类型为* [] byte,则Scan会在该参数中保存一份副本   相应的数据。该副本由调用者拥有,可以   修改并无限期地持有。使用一个可以避免副本   改为类型为* RawBytes的参数;请参阅RawBytes的文档   限制其使用。如果参数的类型为* interface {},   扫描复制底层驱动程序提供的值   转换。如果值是[]字节类型,则复制并且   来电者拥有结果。

如果我使用*[]byte*RawBytes*interface{},可以预期任何速度提升吗?

查看the code,看起来convertAssign() function正在执行许多此特定查询所不需要的内容。所以我的问题是:如何让Scan进程更快?

我考虑过将函数重载以期望预定类型,但在Go中不可能......

有什么想法吗?

1 个答案:

答案 0 :(得分:2)

是的,您可以使用RawBytesrows.Scan()将避免内存分配/复制

关于convertAssign()函数 - 是的,它在Go 1.2中不是最优的, 但是他们在1.3中做出了重大改进 - http://code.google.com/p/go/issues/detail?id=7086
- sync.Pool的无锁实现

我有一些RawBytes用法示例 - https://gist.github.com/yvasiyarov/9911956

此代码从MySQL表中读取数据,进行一些处理并将其写入CSV文件。 昨晚需要1分24秒才能生成4GB的CSV数据(约3000万行)

所以我很清楚在代码之外还有什么问题:rows.Scan()更糟糕的使用方法不能让你延迟10秒。