我用C语言编写服务器软件,我将有大约8个函数从SQLite数据库中选择数据并以某种方式处理它。我正在考虑制作一个函数来发送任何类型的SQLite SELECT命令并将其结果作为指向整数和字符串的指针的2D数组返回,然后让所有函数使用它,但我担心性能成本可能会那么大它不值得额外的可扩展性。提前阅读,这是一个有效的关注吗?
SQLite无法提前计算结果的行数,因此我必须运行两个查询或使用动态分配的数组。不好!以下是我实施后一种选择的方法。我是新手,所以在我承诺使用它之前,请告诉我是否有任何缓慢,不洁或(最重要的)不可靠的事情:
//emalloc and erealloc are just error-detecting malloc and realloc
ptrdiff_t** databaseSelect(char* command){ //returns null upon error
sqlite3_stmt *stmt;
int retval = -1; retval = sqlite3_prepare(db,command,sizeof(command),&stmt,NULL);
if(retval!=SQLITE_OK){
printf("Selecting data from database failed! Error: %s\n", sqlite3_errmsg(db));
return NULL;
}
int retRows = 10; //number of rows in returned array for now
ptrdiff_t** ret = emalloc(sizeof(ptrdiff_t*)*retRows); //make the array representing rows
int result = SQLITE_ROW;
int rowIndex = 0;
while (result != SQLITE_DONE && result != SQLITE_ERROR){
result = sqlite3_step (stmt);
if (result == SQLITE_ROW) { //begin row loop
if ((rowIndex+1)>retRows){ //must reallocate the outer (row) array
retRows*=2;
ret = erealloc(ret, sizeof(ptrdiff_t*)*retRows);
}
const int numCols = sqlite3_column_count(stmt);
ptrdiff_t* row = emalloc(sizeof(ptrdiff_t)*numCols); //make the array representing a row of columns
for (int colIndex = 0; colIndex<numCols; colIndex++){ //begin column loop
switch (sqlite3_column_type(stmt, colIndex)){
case SQLITE_INTEGER:{
const int col = sqlite3_column_int(stmt, colIndex);
memcpy(row[colIndex], &col, sizeof(col));
break;
}
case SQLITE_TEXT:{
const unsigned char* textResult = sqlite3_column_text(stmt, colIndex);
const size_t textSize = (strlen(textResult)+1)*sizeof(char); //edited from before
row[colIndex] = emalloc(textSize);
memcpy(row[colIndex], textResult, textSize);
break;
}
default:{
//perhaps warn about an error since it should either be integer or text
break;
}
}
} //end column loop
ret[rowIndex] = row; //add on the row to the array of rows
rowIndex++;
} //end row loop
}
sqlite3_free(stmt);
return ret;
}
...然后无论这个函数有什么调用都要循环遍历2D数组,并且一旦完成它就释放所有内容。
答案 0 :(得分:1)
对于微小的结果,性能并不重要。
使用常量因子重新分配是创建动态大小数组的最有效方法之一。创建链接会更快,但以后不容易访问。
游标是一个允许(仅)访问当前记录的对象,但如果您需要随机访问所有结果记录,则这不起作用。
请注意,确定文本值长度的最有效方法是sqlite3_column_bytes
:
char *textResult = (char *)sqlite3_column_text(stmt, colIndex);
if (!textResult) textResult = ""; // handle NULL (if needed)
int textSize = sqlite3_column_bytes(stmt, colIndex) + 1;