
package mainimport ( "fmt" "database/sql" _ "github.com/mattn/go-sqlite3" "log" "time")func main() { start := time.Now() db,err := sql.Open("sqlite3","/Users/robertking/go/src/bitbucket.org/thematicanalysis/optimization_test/robs.db") if err != nil { log.Fatal(err) } defer db.Close() rows,err := db.query("select * from data") if err != nil { log.Fatal(err) } defer rows.Close() for rows.Next() { } err = rows.Err() if err != nil { log.Fatal(err) } fmt.Println(time.Since(start))} 这在Go中需要8秒,因为.Next是slow.在python中,一个fetchall只需要4秒!我在GO中重写以获得性能而不会失去性能。
这是python代码,我在go中找不到相同的fetchall:
import timestart = time.time()import sqlite3conn = sqlite3.connect('/Users/robertking/go/src/bitbucket.org/thematicanalysis/optimization_test/robs.db')c = conn.cursor()c.execute("SELECT * FROM data")x = c.fetchall()print time.time() - start 编辑:添加赏金。我正在读取go,python和C中的数据,这里是结果。不想使用C,但如果GO不快,将坚持使用python:
py: 2.45sgo: 2.13s (using github.com/mxk/go-sqlite/sqlite3 instead of github.com/mattn/go-sqlite3)c: 0.32s
我觉得应该更接近c方面的东西?有谁知道如何让它更快?是否可以通过只读模式避免互斥?
编辑:
似乎所有的sqlite3实现都很慢(太多的反射和过多的cgo调用转换)。所以我必须编写自己的界面。
这是架构:
CREATE table mytable( c0 REAL,c1 INTEGER,c15 TEXT,c16 TEXT,c17 TEXT,c18 TEXT,c19 TEXT,c47 TEXT,c74 REAL DEFAulT 0,c77 TEXT,c101 TEXT,c103 TEXT,c108 TEXT,c110 TEXT,c125 TEXT,c126 TEXT,c127 REAL DEFAulT 0,x INTEGER PRIMARY KEY);
并且查询是动态的,但通常是这样的:
SELECT c77,c77,c125,c126,c127,c74 from mytable
编辑:
看起来我会分叉sqlite3实现并制作一些专注于性能的方法,
这是一些代码的例子,速度要快得多:
package main/* #cgo LDFLAGS: -l sqlite3#include "sqlite3.h"*/import "C"import ( //"database/sql" "log" "reflect" "unsafe")type Row struct { v77 string v125 string v126 string v127 float64 v74 float64}// cStr returns a pointer to the first byte in s.func cStr(s string) *C.char { h := (*reflect.Stringheader)(unsafe.Pointer(&s)) return (*C.char)(unsafe.Pointer(h.Data))}func main() { getDataFromsqlite()}func getDataFromsqlite() { var db *C.sqlite3 name := "../data_dbs/all_columns.db" rc := C.sqlite3_open_v2(cStr(name+"\x00"),&db,C.sqlITE_OPEN_Readonly,nil) var stmt *C.sqlite3_stmt; rc = C.sqlite3_prepare_v2(db,cStr("SELECT c77,c74 from data\x00"),C.int(-1),&stmt,nil); rc = C.sqlite3_reset(stmt); var result C.double result = 0.0 rc = C.sqlite3_step(stmt) for rc == C.sqlITE_ROW { C.GoString((*C.char)(unsafe.Pointer(C.sqlite3_column_text(stmt,0)))) C.GoString((*C.char)(unsafe.Pointer(C.sqlite3_column_text(stmt,1)))) C.GoString((*C.char)(unsafe.Pointer(C.sqlite3_column_text(stmt,2)))) C.sqlite3_column_double(stmt,3) result += C.sqlite3_column_double(stmt,4) rc = C.sqlite3_step(stmt) } log.Println(result)} 介绍 我的假设是我们在这里测量性能的方法存在问题,因此我编写了一个Go程序来生成记录并将它们保存到sqlite数据库以及Python和Go实现这些记录的小任务。 。
您可以在https://github.com/mwmahlberg/sqlite3perf找到相应的存储库
数据模型
生成的记录包括
> ID:A row ID generated by SQLite
>兰特:A hex encoded 8 byte pseudo-random value
> hash:A hex encoded SHA256 hash of the unencoded rand
表的架构相对简单:
sqlite> .schemaCREATE table bench (ID int PRIMARY KEY ASC,rand TEXT,hash TEXT);
首先,我生成了1.5M记录,然后使用了sqlite数据库
$ ./sqlite3perf generate -r 1500000 -v
接下来,我针对这些1.5M记录调用了Go实现。 Go以及Python实现基本上都执行相同的简单任务:
>读取数据库中的所有条目。
>对于每一行,从十六进制解码随机值,然后从结果中创建一个SHA256十六进制。
>将生成的SHA256十六进制字符串与存储在数据库中的字符串进行比较
>如果匹配,继续,否则打破。
假设
我明确的假设是Python做了某种类型的延迟加载和/或甚至可能执行SQL查询。
结果
去实施
$ ./sqlite3perf bench2017/12/31 15:21:48 bench called2017/12/31 15:21:48 Time after query: 4.824009ms2017/12/31 15:21:48 Beginning loop2017/12/31 15:21:48 Acessing the first result set ID 0,rand: 6a8a4ad02e5e872a,hash: 571f1053a7c2aaa56e5c076e69389deb4db46cc08f5518c66a4bc593e62b9aa4took 548.32µs2017/12/31 15:21:50 641,664 rows processed2017/12/31 15:21:52 1,325,186 rows processed2017/12/31 15:21:53 1,500,000 rows processed2017/12/31 15:21:53 Finished loop after 4.519083493s2017/12/31 15:21:53 Average 3.015µs per record,4.523936078s overall
请注意“查询后的时间”(查询命令返回的时间)的值以及在结束集开始迭代后访问第一个结果集所花费的时间。
Python实现
$ python bench.py 12/31/2017 15:25:41 Starting up12/31/2017 15:25:41 Time after query: 1874µs12/31/2017 15:25:41 Beginning loop12/31/2017 15:25:44 Accessing first result set ID: 0 rand: 6a8a4ad02e5e872a hash: 571f1053a7c2aaa56e5c076e69389deb4db46cc08f5518c66a4bc593e62b9aa4took 2.719312 s12/31/2017 15:25:50 Finished loop after 9.147431s12/31/2017 15:25:50 Average: 6.098µs per record,0:00:09.149522 overall
再次,请注意“查询后的时间”的值以及访问第一个结果集所花费的时间。
概要
在发送SELECT查询之后,Go实现需要很长时间才能返回,而Python似乎比较快速。但是,从实际访问第一个结果集所花费的时间开始,我们可以看到Go实现比实际访问第一个结果集(5.372329ms vs 2719.312ms)快了500倍,并且任务速度快了两倍手头上的Python实现。
笔记
>为了证明Python实际上对结果集进行延迟加载的假设,必须访问每一行和每一行,以确保Python被强制实际读取数据库中的值。
>我选择了哈希任务,因为可能是SHA256的实现在两种语言中都得到了高度优化。
结论
Python似乎确实延迟加载结果集,甚至可能甚至不执行查询,除非实际访问了相应的结果集。在这个模拟场景中,对于Go来说,mattn的sqlite驱动程序的性能大约在100%到几个数量级之间,具体取决于你想要做什么。
编辑:因此,为了快速处理,请在Go中执行您的任务。虽然发送实际查询需要更长时间,但访问结果集的各个行的速度要快得多。我建议从一小部分数据开始,比如50k记录。然后,为了进一步改进您的代码,请使用profiling来识别您的瓶颈。例如,根据您在处理期间要执行的 *** 作,pipelines可能会有所帮助,但如果没有实际代码或详细说明,很难说如何提高手头任务的处理速度。
总结以上是内存溢出为你收集整理的更快的sqlite 3查询?我需要尽快处理100万行全部内容,希望文章能够帮你解决更快的sqlite 3查询?我需要尽快处理100万行所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)