简介本文向大家介绍一个C++实战项目:C++中SQLite与文件系统I0读写性能比较,主要介绍SQLite数据库的优缺点,以及在同样条件下SQLite与文件系统IO读写性能比较,具有一定的C++实战价值,感兴趣的朋友可以参考一下。
SQLite是一个C语言库,它实现了一个小型、快速、自包含、高可靠性、全功能的SQL数据库引擎。SQLite 读写效率比较高,有如下优点:
主要优点总结: 轻量 高效 跨平台 单文件 开源
为了比较C++中文件系统与SQLite读写性能,使用VS2015创建一个名为“WriteToFileAndSQLite”的对话框工程:
其中,实现写入功能代码如下:
// 写入到文件
void CWriteToFileAndSQLiteDlg::OnBnClickedBtnWriteFile()
{
OnBtnWrite(1);
}
// 写入到SQLite
void CWriteToFileAndSQLiteDlg::OnBnClickedBtnWriteSqlite()
{
OnBtnWrite(2);
}
// 写入按钮事件
void CWriteToFileAndSQLiteDlg::OnBtnWrite(int iWriteFlag)
{
UpdateData(TRUE);
if (m_strWriteCount.IsEmpty())
{
MessageBox(_T("未输入写入行数!"), _T("系统提示"), 0);
return;
}
m_iWriteFlag = iWriteFlag;
HANDLE hThread = CreateThread(NULL, 0, WriteThread, (LPVOID)this, 0, NULL);
CloseHandle(hThread);
}
// 获取写入内容
std::string CWriteToFileAndSQLiteDlg::GetContent(int nID)
{
USES_CONVERSION;
srand((unsigned)time(NULL));
CString sTemp = _T("");
sTemp.Format(_T("%07d"), nID);
Json::Value student;
student["ID"] = T2A(sTemp);
sTemp.Format(_T("学生%d"), nID);
student["Name"] = T2A(sTemp);
student["Grade"] = rand() % 100;
Json::FastWriter fw;
return fw.write(student);
}
DWORD WINAPI WriteThread(void* pVoid)
{
CWriteToFileAndSQLiteDlg* pMainWnd = (CWriteToFileAndSQLiteDlg*)pVoid;
if (pMainWnd)
{
pMainWnd->WriteThreadFunc();
}
return 0;
}
void CWriteToFileAndSQLiteDlg::WriteThreadFunc()
{
GetDlgItem(ID_BTN_WRITE_FILE)->EnableWindow(FALSE);
GetDlgItem(ID_BTN_WRITE_SQLITE)->EnableWindow(FALSE);
int iCount = _ttoi(m_strWriteCount);
// 写入到文件
if (m_iWriteFlag == 1)
{
USES_CONVERSION;
CString strFilePath = Util::GetCurrentPath() + _T("\\student.txt");
std::ofstream os;
os.open(T2A(strFilePath), std::ios::out);
if (!os.fail())
{
std::vector vecContent;
for (int i = 0; i < iCount; ++i)
{
vecContent.push_back(GetContent(i + 1));
}
// 获取当前时间
WriteLog("写入到文件(%d行)开始...", iCount);
double start_time = GetTickCount();
for (unsigned int i = 0; i < vecContent.size(); ++i)
{
os << vecContent[i].c_str();
}
double end_time = GetTickCount();
double dSecond = end_time - start_time;
WriteLog("写入到文件(%d行)结束 --> 用时:%.6fms", iCount, dSecond);
os.close();
}
else
{
WriteLog("写入文件失败...");
}
}
else
{
CString strDbPath = Util::GetCurrentPath() + _T("\\student.db3");
CStudentSqlite BbStudent(strDbPath);
BbStudent.Clear();
StudentGradeInfoVec vecGradeInfo;
srand((unsigned)time(NULL));
for (int i = 0; i < iCount; ++i)
{
STUDENT_GRADE_INFO StuGradeInfo;
StuGradeInfo.ID.Format(_T("%07d"), i + 1);
StuGradeInfo.Name.Format(_T("学生%d"), i + 1);
StuGradeInfo.Grade = rand() % 100;
vecGradeInfo.push_back(StuGradeInfo);
}
WriteLog("写入到SQLite(%d行)开始...", iCount);
double start_time = GetTickCount();
for (unsigned int i = 0; i < iCount; ++i)
{
BbStudent.AddRecordToTableGrade(vecGradeInfo[i]);
}
double end_time = GetTickCount();
double dSecond = end_time - start_time;
WriteLog("写入到SQLite(%d行)结束 --> 用时:%.6fms", iCount, dSecond);
}
GetDlgItem(ID_BTN_WRITE_FILE)->EnableWindow(TRUE);
GetDlgItem(ID_BTN_WRITE_SQLITE)->EnableWindow(TRUE);
}
写入500行,执行完毕后在程序运行目录下会生成如下文件:
测试结果如下:
可见:同样的写入功能,SQLite性能要比系统IO慢很多,这里注意每次测试结果不一定一样,但结果相差不大。
为何相差如此之大,这里是因为写入数据库的时候是一条一条写入的,速度会慢很多:
// 写入一行
bool CStudentSqlite::AddRecordToTableGrade(const STUDENT_GRADE_INFO& pStuGradeInfo)
{
try
{
CString strSQL = _T("");
strSQL.Format(_T("INSERT INTO 学生成绩表 VALUES('%s', '%s', %d);"), pStuGradeInfo.ID, pStuGradeInfo.Name, pStuGradeInfo.Grade);
execDML(strSQL);
return true;
}
catch (CppSQLite3Exception &e)
{
TRACE("CStudentSqlite::AddRecordToTableGrade %s", e.errorMessage());
}
return false;
}
改成SQLite一次插入多条记录:
// 写入多行
bool CStudentSqlite::AddRecordsToTableGrade(const StudentGradeInfoVec& vStudentGradeInfo)
{
try
{
if (vStudentGradeInfo.size() > 0)
{
if (vStudentGradeInfo.size() == 1)
{
return AddRecordToTableGrade(vStudentGradeInfo[0]);
}
else
{
CString strSQL = _T("");
strSQL.Format(_T("INSERT INTO 学生成绩表(ID,Name,Grade) SELECT '%s' AS 'ID', '%s' AS 'Name', '%d' AS 'Grade' "), vStudentGradeInfo[0].ID, vStudentGradeInfo[0].Name, vStudentGradeInfo[0].Grade);
CString sTemp = _T("");
for (unsigned int i = 1; i < vStudentGradeInfo.size(); ++i)
{
sTemp.Format(_T("union select '%s','%s','%d' "), vStudentGradeInfo[i].ID, vStudentGradeInfo[i].Name, vStudentGradeInfo[i].Grade);
strSQL += sTemp;
}
execDML(strSQL);
return true;
}
}
}
catch (CppSQLite3Exception &e)
{
TRACE("CStudentSqlite::AddRecordToTableGrade %s", e.errorMessage());
}
return false;
}
double start_time = GetTickCount();
BbStudent.AddRecordsToTableGrade(vecGradeInfo);
double end_time = GetTickCount();
double dSecond = end_time - start_time;
WriteLog("写入到SQLite(%d行)结束 --> 用时:%.6fms", iCount, dSecond);
测试结果如下:
可见多条记录一次性插入速度明显是快多了。
接下来实现读取功能代码如下:
// 从文件读取
void CWriteToFileAndSQLiteDlg::OnBnClickedBtnReadFile()
{
m_iReadFlag = 1;
HANDLE hThread = CreateThread(NULL, 0, ReadThread, (LPVOID)this, 0, NULL);
CloseHandle(hThread);
}
// 从SQLite读取
void CWriteToFileAndSQLiteDlg::OnBnClickedBtnReadSqlite()
{
m_iReadFlag = 2;
HANDLE hThread = CreateThread(NULL, 0, ReadThread, (LPVOID)this, 0, NULL);
CloseHandle(hThread);
}
DWORD WINAPI ReadThread(void* pVoid)
{
CWriteToFileAndSQLiteDlg* pMainWnd = (CWriteToFileAndSQLiteDlg*)pVoid;
if (pMainWnd)
{
pMainWnd->ReadThreadFunc();
}
return 0;
}
// 读取线程函数
void CWriteToFileAndSQLiteDlg::ReadThreadFunc()
{
GetDlgItem(ID_BTN_READ_FILE)->EnableWindow(FALSE);
GetDlgItem(ID_BTN_READ_SQLITE)->EnableWindow(FALSE);
USES_CONVERSION;
// 从文件读取
if (m_iReadFlag == 1)
{
USES_CONVERSION;
CString strFilePath = Util::GetCurrentPath() + _T("\\student.txt");
// 只读
std::ifstream ifs(T2A(strFilePath), std::ios_base::in);
if (ifs.is_open())
{
WriteLog("从文件读取 开始...");
double start_time = GetTickCount();
char* pBuf = new char[256];
while (!ifs.eof())
{
ifs.getline(pBuf, 256);
//WriteLog("%s", pBuf);
}
double end_time = GetTickCount();
double dSecond = end_time - start_time;
WriteLog("从文件读取 结束 --> 用时:%.6fms", dSecond);
ifs.close();
delete[] pBuf;
}
else
{
WriteLog("读取文件失败...");
}
}
else
{
CString strDbPath = Util::GetCurrentPath() + _T("\\student.db3");;
CStudentSqlite BbStudent(strDbPath);
std::vector<CString> vecGradeInfo;
WriteLog("从SQLite读取 开始...");
double start_time = GetTickCount();
BbStudent.ReadRecordFromTableGrade(vecGradeInfo);
double end_time = GetTickCount();
double dSecond = end_time - start_time;
WriteLog("从SQLite读取 结束 --> 用时:%.6fms", dSecond);
}
GetDlgItem(ID_BTN_READ_FILE)->EnableWindow(TRUE);
GetDlgItem(ID_BTN_READ_SQLITE)->EnableWindow(TRUE);
}
测试结果如下:
可见:同样读取500行,SQLite性能要和系统I/O几乎相同,但随着数据量的增大,SQLite的读取性能会比系统I/O差很多。
最后总结,在考虑是否采用SQLite数据库的时候,建议考虑以下场景:
本文向大家介绍一个C++实战项目:基于MFC中SQLite3数据库操作快速入门,主要介绍MFC中对SQLite3数据库的创建、数据查询、删除等常见操作,并对其进行封装操作,具有一定的C++实战价值,感兴趣的朋友可以参考一下。
本文向大家介绍一个C++实战项目:C++中SQLite多行数据一次性写入,提高多行数据插入到SQLite数据库中的速度,具有一定的C++实战价值,感兴趣的朋友可以参考一下。
本文向大家介绍一个C++实战项目:C++实现一个SQL数据库连测试工具,具有一定的C++实战价值,感兴趣的朋友可以参考一下。
本文向大家介绍一个C++实战项目:基于Win32工程C++连接MYSQL数据库,主要介绍C++如何快速连接MySQL数据库并执行SQL语句,具有一定的C++实战价值,感兴趣的朋友可以参考一下。
本文向大家介绍C++实现对MySQL访问操作的封装类,感兴趣的朋友可以参考一下。
本文向大家介绍一个C++实战项目:C++实现对SQL Server访问操作的封装类,具有一定的C++实战价值,感兴趣的朋友可以参考一下。