- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
优化 SQLite 很棘手。 C 应用程序的批量插入性能可以从每秒 85 次插入到每秒超过 96,000 次插入不等!
背景:我们使用 SQLite 作为桌面应用程序的一部分。我们将大量配置数据存储在 XML 文件中,这些数据会在应用程序初始化时被解析并加载到 SQLite 数据库中以供进一步处理。 SQLite 非常适合这种情况,因为它速度快,不需要专门的配置,并且数据库作为单个文件存储在磁盘上。
理由:最初我对我所看到的表现感到失望。事实证明,根据数据库的配置方式以及您使用 API 的方式,SQLite 的性能可能会有很大差异(对于批量插入和选择)。弄清楚所有选项和技术是什么并不是一件容易的事,所以我认为创建这个社区 wiki 条目以与 StackOverflow 读者分享结果是明智的,以便为其他人避免相同调查的麻烦。
实验:与其简单地谈论一般意义上的性能技巧(即“使用事务!”),我认为最好编写一些 C 代码并实际衡量各种选项的影响。我们将从一些简单的数据开始:
/*************************************************************
Baseline code to experiment with SQLite performance.
Input data is a 28 MB TAB-delimited text file of the
complete Toronto Transit System schedule/route info
from http://www.toronto.ca/open/datasets/ttc-routes/
**************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "sqlite3.h"
#define INPUTDATA "C:\\TTC_schedule_scheduleitem_10-27-2009.txt"
#define DATABASE "c:\\TTC_schedule_scheduleitem_10-27-2009.sqlite"
#define TABLE "CREATE TABLE IF NOT EXISTS TTC (id INTEGER PRIMARY KEY, Route_ID TEXT, Branch_Code TEXT, Version INTEGER, Stop INTEGER, Vehicle_Index INTEGER, Day Integer, Time TEXT)"
#define BUFFER_SIZE 256
int main(int argc, char **argv) {
sqlite3 * db;
sqlite3_stmt * stmt;
char * sErrMsg = 0;
char * tail = 0;
int nRetCode;
int n = 0;
clock_t cStartClock;
FILE * pFile;
char sInputBuf [BUFFER_SIZE] = "\0";
char * sRT = 0; /* Route */
char * sBR = 0; /* Branch */
char * sVR = 0; /* Version */
char * sST = 0; /* Stop Number */
char * sVI = 0; /* Vehicle */
char * sDT = 0; /* Date */
char * sTM = 0; /* Time */
char sSQL [BUFFER_SIZE] = "\0";
/*********************************************/
/* Open the Database and create the Schema */
sqlite3_open(DATABASE, &db);
sqlite3_exec(db, TABLE, NULL, NULL, &sErrMsg);
/*********************************************/
/* Open input file and import into Database*/
cStartClock = clock();
pFile = fopen (INPUTDATA,"r");
while (!feof(pFile)) {
fgets (sInputBuf, BUFFER_SIZE, pFile);
sRT = strtok (sInputBuf, "\t"); /* Get Route */
sBR = strtok (NULL, "\t"); /* Get Branch */
sVR = strtok (NULL, "\t"); /* Get Version */
sST = strtok (NULL, "\t"); /* Get Stop Number */
sVI = strtok (NULL, "\t"); /* Get Vehicle */
sDT = strtok (NULL, "\t"); /* Get Date */
sTM = strtok (NULL, "\t"); /* Get Time */
/* ACTUAL INSERT WILL GO HERE */
n++;
}
fclose (pFile);
printf("Imported %d records in %4.2f seconds\n", n, (clock() - cStartClock) / (double)CLOCKS_PER_SEC);
sqlite3_close(db);
return 0;
}
Imported 864913 records in 0.94seconds
sprintf(sSQL, "INSERT INTO TTC VALUES (NULL, '%s', '%s', '%s', '%s', '%s', '%s', '%s')", sRT, sBR, sVR, sST, sVI, sDT, sTM);
sqlite3_exec(db, sSQL, NULL, NULL, &sErrMsg);
这会很慢,因为每次插入都会将 SQL 编译为 VDBE 代码,并且每次插入都将在其自己的事务中发生。有多慢?
Imported 864913 records in 9933.61seconds
sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, &sErrMsg);
pFile = fopen (INPUTDATA,"r");
while (!feof(pFile)) {
...
}
fclose (pFile);
sqlite3_exec(db, "END TRANSACTION", NULL, NULL, &sErrMsg);
Imported 864913 records in 38.03seconds
sqlite3_prepare_v2
编译一次我们的 SQL 语句,然后使用
sqlite3_bind_text
将我们的参数绑定(bind)到该语句。 :
/* Open input file and import into the database */
cStartClock = clock();
sprintf(sSQL, "INSERT INTO TTC VALUES (NULL, @RT, @BR, @VR, @ST, @VI, @DT, @TM)");
sqlite3_prepare_v2(db, sSQL, BUFFER_SIZE, &stmt, &tail);
sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, &sErrMsg);
pFile = fopen (INPUTDATA,"r");
while (!feof(pFile)) {
fgets (sInputBuf, BUFFER_SIZE, pFile);
sRT = strtok (sInputBuf, "\t"); /* Get Route */
sBR = strtok (NULL, "\t"); /* Get Branch */
sVR = strtok (NULL, "\t"); /* Get Version */
sST = strtok (NULL, "\t"); /* Get Stop Number */
sVI = strtok (NULL, "\t"); /* Get Vehicle */
sDT = strtok (NULL, "\t"); /* Get Date */
sTM = strtok (NULL, "\t"); /* Get Time */
sqlite3_bind_text(stmt, 1, sRT, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, sBR, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 3, sVR, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 4, sST, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 5, sVI, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 6, sDT, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 7, sTM, -1, SQLITE_TRANSIENT);
sqlite3_step(stmt);
sqlite3_clear_bindings(stmt);
sqlite3_reset(stmt);
n++;
}
fclose (pFile);
sqlite3_exec(db, "END TRANSACTION", NULL, NULL, &sErrMsg);
printf("Imported %d records in %4.2f seconds\n", n, (clock() - cStartClock) / (double)CLOCKS_PER_SEC);
sqlite3_finalize(stmt);
sqlite3_close(db);
return 0;
Imported 864913 records in 16.27seconds
sqlite3_clear_bindings
和
sqlite3_reset
),但我们的性能提高了一倍多到
每秒 53,000 次插入。
synchronous = OFF
,我们正在指示 SQLite 简单地将数据移交给操作系统进行写入,然后继续。如果计算机在将数据写入盘片之前发生灾难性崩溃(或电源故障),则数据库文件可能会损坏:
/* Open the database and create the schema */
sqlite3_open(DATABASE, &db);
sqlite3_exec(db, TABLE, NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA synchronous = OFF", NULL, NULL, &sErrMsg);
Imported 864913 records in 12.41seconds
PRAGMA journal_mode = MEMORY
将回滚日志存储在内存中.您的交易会更快,但如果您在交易期间断电或程序崩溃,您的数据库可能会因部分完成的交易而处于损坏状态:
/* Open the database and create the schema */
sqlite3_open(DATABASE, &db);
sqlite3_exec(db, TABLE, NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA journal_mode = MEMORY", NULL, NULL, &sErrMsg);
Imported 864913 records in 13.50seconds
/* Open the database and create the schema */
sqlite3_open(DATABASE, &db);
sqlite3_exec(db, TABLE, NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA synchronous = OFF", NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA journal_mode = MEMORY", NULL, NULL, &sErrMsg);
Imported 864913 records in 12.00seconds
#define DATABASE ":memory:"
Imported 864913 records in 10.94seconds
char*
while
中的赋值操作环形。让我们快速重构该代码以传递
strtok()
的输出直接进入
sqlite3_bind_text()
,并让编译器尝试为我们加快速度:
pFile = fopen (INPUTDATA,"r");
while (!feof(pFile)) {
fgets (sInputBuf, BUFFER_SIZE, pFile);
sqlite3_bind_text(stmt, 1, strtok (sInputBuf, "\t"), -1, SQLITE_TRANSIENT); /* Get Route */
sqlite3_bind_text(stmt, 2, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT); /* Get Branch */
sqlite3_bind_text(stmt, 3, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT); /* Get Version */
sqlite3_bind_text(stmt, 4, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT); /* Get Stop Number */
sqlite3_bind_text(stmt, 5, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT); /* Get Vehicle */
sqlite3_bind_text(stmt, 6, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT); /* Get Date */
sqlite3_bind_text(stmt, 7, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT); /* Get Time */
sqlite3_step(stmt); /* Execute the SQL Statement */
sqlite3_clear_bindings(stmt); /* Clear bindings */
sqlite3_reset(stmt); /* Reset VDBE */
n++;
}
fclose (pFile);
注意:我们又回到使用真正的数据库文件了。内存数据库速度很快,但不一定实用
Imported 864913 records in 8.94seconds
SELECT
性能,我们知道我们将创建索引。在下面的一个答案中建议,在进行批量插入时,插入数据后创建索引会更快(而不是先创建索引然后插入数据)。我们试试看:
sqlite3_exec(db, "CREATE INDEX 'TTC_Stop_Index' ON 'TTC' ('Stop')", NULL, NULL, &sErrMsg);
sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, &sErrMsg);
...
Imported 864913 records in 18.13seconds
...
sqlite3_exec(db, "END TRANSACTION", NULL, NULL, &sErrMsg);
sqlite3_exec(db, "CREATE INDEX 'TTC_Stop_Index' ON 'TTC' ('Stop')", NULL, NULL, &sErrMsg);
Imported 864913 records in 13.66seconds
最佳答案
几个提示:
pragma journal_mode
)。有NORMAL
,然后是 OFF
,如果您不太担心操作系统崩溃时数据库可能会损坏,这可以显着提高插入速度。如果您的应用程序崩溃,数据应该没问题。请注意,在较新版本中,OFF/MEMORY
设置对于应用程序级别的崩溃是不安全的。 PRAGMA page_size
)。由于较大的页面保存在内存中,因此具有较大的页面大小可以使读取和写入速度更快。请注意,更多内存将用于您的数据库。 CREATE INDEX
完成所有插入后。这比创建索引然后进行插入要快得多。 INTEGER PRIMARY KEY
如果可能,它将替换表中隐含的唯一行号列。 !feof(file)
! 关于c - 提高 SQLite 的每秒插入性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1711631/
我想要一个按钮,单击该按钮会在指定时间后刷新当前页面。 我目前有: setTimeout(function reload(){ location = '' },1000) Relo
我有一个场景,我需要每秒向服务器发送数据(非常少的字节)。这个细节很重要,所以我也需要对其进行加密。 深入研究后,我认为我们可以使用 HTTP 协议(protocol),但在这种情况下,HTTP he
我在即将进行的测试的学习指南中得到了这个问题。我不明白如何解决这个问题。今天是我的考试,我希望能得到一些帮助。 如果 CPU 每条指令发出一个内存请求并且计算机以 200 MIPS 运行,大约需要多少
我正在编写一个程序来确定每秒可以运行多少个 NOP,但我得到的数字似乎非常小。 int main() { struct timeval tvStart, tvDiff, tvEnd;
我想实现每秒 5-1 百万次远程函数调用。假设我们有一台开始计算的 Central 计算机,还有一台执行计算的 Worker 计算机。实际配置中会有很多Worker计算机。 假设我们的任务是计算一个[
下面的代码向最后一个 div 添加了一个类: $(".mydivs:last").addClass('added'); 这适用于页面加载,但 div 在动画中,因此顺序会改变。有没有办法让代码每秒运行
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwa
我刚刚在 HBase 中创建了一个表并用数据填充了它。从 7 个区域服务器看来,数据已写入区域服务器 6 和 7。 但我不明白为什么服务器 6 和 7 的每秒请求数为零? 最佳答案 读取请求计数 和写
我正在开发一个聊天应用程序,需要您的帮助。如果有人在线,我将信息存储在数据库中。现在我有一个功能,可以显示您的好友列表以及聊天伙伴是否在线。问题是:如果有人上网,我想经常检查。到目前为止,我有一个每秒
我正在编写一个快速而肮脏的脚本来检测服务器停机时间。我有一台服务器和两个远程客户端,它们每秒对服务器执行一次 ping 操作以查看它是否已启动。 如果您最多可以每分钟运行一次 cron,我该如何设置任
有什么方法可以让 Graphite 绘制图表请求吗? 当你从 nginx_status 检索 nginx 请求时,你正在向 Graphite 发送一个绝对值,所以我在想是否有任何方法可以获取每秒的速率
我正在构建一个 Android 应用程序,它将加速度计和陀螺仪数据记录到文本文件中。在大多数教程中,他们使用的方法涉及创建两个文本文件,并每秒打开和关闭它们 50 次。即: private stati
嘿,我目前在我的 mysql 上有超过 300+ qps。在相当繁重的 PHP 网站上大约有 12000 UIP 一天/没有 cron。我知道在没有看到该网站的情况下很难判断是否可以,但您是否认为这完
我希望每秒钟使用我的鼠标移动功能旋转矩形我做错了什么?我怎样才能做我的变换,以便高度和旋转每隔一个元素改变一次?我用 if ( i % 2 == 0){} 试了一下 function modifyRe
有没有办法配置具有恒定负载的性能测试用例(例如,每秒 3 个新请求,持续 1 分钟)? 其他负载测试库具有此功能来设置请求率(例如 Artillery.io、Vegeta)。 k6 有设置VUs 的方
(只是想提一下,这是我的第一个问题,如果我做错了什么,我深表歉意)。我正在制作一个解析 CSV 文件并将其保存为列表的 Python 程序。但是,该程序需要用户输入他们希望将数据发送到服务器的速度。我
如何使用 python 将毫秒转换为帧数?我知道视频的帧速率(每帧 25 秒) 2683480 2684448 最佳答案 我最终决定手动执行此操作,因为我仍然没有弄清楚 ffmpeg 函数等 25fp
我有一个动态表,它按从主要编号到次要编号的降序排列。我想用 jQuery 在前 2 行放置红色背景,在接下来的行放置橙色背景,在接下来的 2 行放置黄色背景,在接下来的 3 行放置绿色背景。 表结构:
构建 Rails 应用程序 (ruby 2.4.0p0/Rails 5.1.4) 并使用我的 Macbook air (MacOS High Sierra 10.13.2) 在本地进行测试,但我一直遇
这个问题已经有答案了: NSTimer not firing when runloop is blocked (2 个回答) 已关闭 9 年前。 我使用 NSTimer,它每秒触发一次并更新一个标签,
我是一名优秀的程序员,十分优秀!