sqlite32013.12.30 12:14

sqlite> pragma table_info(delivery);

0|key|varchar(65)|0||1

1|nick_src|varchar(65)|0||0

2|nick_tgt|varchar(65)|0||0

3|date_send|varchar(33)|0||0

4|date_recv|varchar(33)|0||0

5|item|varchar(33)|0||0

6|msg|varchar(81)|0||0



delivery.date_send 는  "20131201.1230" 형태의 문자열로 저장되어 있는 컬럼이다. 이것을 비교하여 쿼리하기 위해서는 CAST함수를 이용한다. 


sqlite> delete from delivery where CAST(date_send as integer) < 20131201;
sqlite>


date_send(보낸 날짜)가 12월01일 이전인 레코드를 삭제하려는 목적인데, 이렇게 하면 잘 동작한다.
※ 처리속도는 매우 느리므로, 유지관리작업중에나 사용 가능한 점에 유의. 


Posted by Jadumate
sqlite32013.12.30 12:10

delete from [table] 로 레코드를 엄청나게 줄였음에도, 물리적 파일 사이즈는 줄어들지 않는다. 디스크 공간을 재사용하기 위해서인데, 이 경우 vacuum 명령어로 실제 파일 사이즈를 줄일수 있다. 


sqlite> vacuum;

sqlite> .quit


[biscuit@*****]$ ls -al sogon.db*

-rw-rw-rw- 1 biscuit users 92,228,608 12월 30 12:05 sogon.db

-rw-r--r-- 1 biscuit users 18,917,376 12월 30 12:05 sogon.db.test


필요없는 레코드들을 지우고나서도 92메가 정도였는데, vacuum 명령어 실행후 확 줄어들었다. 


Posted by Jadumate
sqlite32013.06.11 16:57

그냥 보통 방법으로 INSERT와 DELETE등의 쿼리를 반복적으로 수행할때에 sqlite3의 성능은 형편없이 떨어지는데, 이럴때에는 Transaction을 이용해야 한다. 100개의 INSERT에 5초이상 걸리기도 하니 Transaction은 필수적이다.


int TSqlite::ExecuteMulti(const list<string> &queries)

{

// begin

sqlite3_exec(this->m_db, "BEGIN TRANSACTION;", 0, 0, 0);


list<string>::const_iterator ils = queries.begin();

while(ils != queries.end()){

sqlite3_exec(this->m_db, ils->c_str(), 0, 0, 0);

ils++;

}


// end

sqlite3_exec(this->m_db, "END TRANSACTION;", 0, 0, 0);


return sqlite3_total_changes(this->m_db);

}


sqlite3 stmt를 사용하지 않고, 간단히 구성해 보았다.  BEGIN - query - END 형식으로, 최종적으로 Effected Rows를 돌려주도록 하였다. 

테스트로 INSERT 600개를 연속으로 보냈을때에, 실행시간은 약 5초-> 0.05초로 백배 이상 빨라졌다. 

Posted by Jadumate
sqlite32013.05.24 20:55

sqlite3에 대한 C++ wrapper class 를 만들어 보았다. 


간단하게 INSERT와 SELECT 정도만 편하게 했으면 좋겠다 싶은데, sqlite라는게 그리 간단하지가 않다. (gdbm 정도의 편리함을 기대했다면 오산이다). db를 open하고 close하는 사이에 prepare하고 free, finalize 하는게 생각보다 까다롭다. 


그래서 요것만 후다닥 구현.


class TSqlite

{

protected :

bool m_isError;

sqlite3 *m_db;


private :

bool Send(const char *strQuery);


public:

TSqlite(const char *strFileName)

{

m_isError = (sqlite3_open(strFileName, &m_db) == SQLITE_OK) ? false : true;

}


~TSqlite()

{

if(m_db) sqlite3_close(m_db);

}


bool isError()

{

return m_isError;

}


int Execute(const char *strQuery);

int Select (const char *strQuery, list< vector<string> > &rResult);

};

소스1 : sqlite.h


bool TSqlite::Send(const char *strQuery)

{

    sqlite3_stmt *stmt;

    bool result = true;


    int rc = sqlite3_prepare(this->m_db, strQuery, strlen(strQuery), &stmt, NULL);

    if(rc != SQLITE_OK) return false;


    if(sqlite3_step(stmt) != SQLITE_DONE) {

        fprintf(stderr, "line %d: %s (%s)\n", __LINE__, sqlite3_errmsg(this->m_db), strQeury);

        result = false;

    }

    sqlite3_reset(stmt);

    sqlite3_finalize(stmt);


    return result;

};


int TSqlite::Select(const char *strQuery, list< vector<string> >  &rResult)

{

int  nColumn = 0;

char tbuf[64];

sqlite3_stmt *stmt;

vector<string> row1;


sqlite3_prepare(this->m_db, strQuery, -1, &stmt, NULL);


while(sqlite3_step(stmt) == SQLITE_ROW)

{

nColumn = sqlite3_column_count(stmt);


row1.clear();

for(int i = 0; i < nColumn ; i++) {

switch(sqlite3_column_type(stmt, i)){

case SQLITE_TEXT:

row1.push_back((const char *)sqlite3_column_text(stmt, i));

break;

case SQLITE_INTEGER:

sprintf(tbuf, "%d:", sqlite3_column_int(stmt, i));

row1.push_back(tbuf);

break;

case SQLITE_FLOAT:

sprintf(tbuf, "%f:", sqlite3_column_double(stmt, i));

row1.push_back(tbuf);

break;

case SQLITE_NULL:

break;

default:

break;

}

}

rResult.push_back(row1);

}

sqlite3_reset(stmt);

sqlite3_finalize(stmt);


return rResult.size();

}


int TSqlite::Execute(const char *strQuery)

{

sqlite3_stmt *stmt;

int result = 0;


sqlite3_prepare(this->m_db, strQuery, -1, &stmt, NULL);


// begin

this->Send("BEGIN;");

if(sqlite3_step(stmt) != SQLITE_DONE){

fprintf(stderr, "line %d: %s  (%s)\n", __LINE__, sqlite3_errmsg(this->m_db), strQuery);

result = -1;

}

// commit

this->Send("COMMIT;");


result = sqlite3_total_changes(this->m_db);


sqlite3_reset(stmt);

sqlite3_finalize(stmt);


return result;

}

소스2 sqlite.cc



이렇게 클래스를 만들어 두고 나니, 아래처럼 아주 간단하게 사용할 수 있다. 

TSqlite sql(FILE_MY_DB);

if(sql.isError()) return -1;


// 결과를 받아올 리스트 생성

list< vector<string> > rows;


// 쿼리만들기 & 결과 가져오기

sprintf(strQuery, "SELECT * from table WHERE id = '%s';", strId);

int nRows = sql.Select(strQuery, rows);


// 루프돌면서 결과값 출력

list< vector<string> >::iterator it = rows.begin();

while(it != rows.end()){

      // 레코드 1개 얻어오기

vector<string> &rRow = *it;


// 컬럼별로 출력

for(int i=0; i< rRow.size(); i++)

    cout << rRow[i] << endl;


it++;

}







Posted by Jadumate