sqlite3
sqlite3,众所周知用于单个程序的轻量化数据库。可以比较方便的使用,无额外依赖、开源的特点。
可以结合c、python、java等可以较为方便的使用。
从编译安装开始
从github 选择所需要的版本
而后编译安装
# 依赖
yum install g++ tcl
# 解压后,安装
./configure --prefix=/path
make
make install
export PATH=/path/bin:${PATH}
export CPATH=/path/include:${CPATH}
export LD_LIBRARY_PATH=/path/lib:${LD_LIBRARY_PATH}
#检查版本
sqlite3 -version
于Sql处深入
基本是经典的SQL语法,不过细微处稍有不同。
比如没有事务的if,
这里采取嵌套sql的形式实现。
比如我们需要有条件的插入数据,则采取insert select的组合如下。在select的where中去实现我们的条件。
insert table select col1, col2 where cond;
又比如条件选择值时可以采取case when子句来实现,
update table set col1 = (case
when cond
then val1 else val2 end);
在c语言中探索
sqlite3带有丰富的语言支持,包括但不限于c, c#, java, python。这里主要讨论c中的使用
需要的头文件只有sqlite3.h
而使用过程的话主要是两种范式,他们实际上是递进关系。
sql执行
这个算是最简单的实现手法。定义sql语句,而后执行即可。
// 行结果回调:自定义参数, 列数,结果数组(一行数据),列名数组
static int callback(void *userarg, int argc, char **argv, char **azColName);
// 打开数据库
rc = sqlite3_open("test.db", &db);
rc = sqlite3_exec(db, "select * from table", callback, NULL/*userarg*/, &zErrMsg);
if( rc != SQLITE_OK ){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}else{
fprintf(stdout, "执行成功\n");
}
// 关闭数据库
sqlite3_close(db);
当然为了更高效的查询,可以使用sqlite3_get_table
一次性拉取查询结果表格,替换掉exec操作
SQLITE_API int sqlite3_get_table(
sqlite3 *db, /* An open database */
const char *zSql, /* SQL to be evaluated */
char ***pazResult, /* Results of the query */
int *pnRow, /* Number of result rows written here */
int *pnColumn, /* Number of result columns written here */
char **pzErrmsg /* Error msg written here */
);
SQLITE_API void sqlite3_free_table(char **result);
使用的时候,需要注意的是,
- 结果表格pazResult中,逻辑上他是一个二维表格(元素是字符串指针),但是扁平化了,去掉了行这一维度,也就是第二行在第一行后面接续。
- 第一行是列名,而且不计入行数pnRow中。
预编译、执行
众所周知,sql的执行过程可以分,分析,优化,执行。前两步可以合并成为解析,exec过程实际上是按顺序一次执行完成,但是这将强制每次都全部编译解析,执行步骤,但是实际上sql的内容并没有变化,而我们却要每次都进行编译解析,这显然是浪费的。
sqlite3提供给prepare, step来拆分exec功能,以便降低重复开销。
使用的基本步骤如下:
- sqlite3_prepare_v3
- sqlite3_bind_text
- sqlite3_step
- 如果为SQLITE_ROW则为结果行,可以继续执行
- SQLITE_DONE则标识正常结束
- sqlite3_reset
- sqlite3_clear_bindings
其中2-5步是具体执行过程中需要做的,值得一提的是,常见的教程只叫你reset重置方式,但是不clear bind, 这将导致bind的值始终不变,并不复用,当然不排除这就是需要的。
与优化同去
共3个方向去优化,sql、预编译、多线程
- sql优化,也即规划sql子句步骤,避免多余的空间(如select所需的列而不是全部)、时间开销(尽快where,降低规模等)。
- 预编译也即上一章的内容
- 多线程,这个因为sqlite是文件锁,建议分db,降低冲突