奇妙なsqlite 3のmalformedエラー(一)


奇妙なsqlite 3のmalformedエラー(一)


げんしょう

  • 現場設備が大規模なデータを生成挿入し、設備異常がデータベースを引き出して検査する場合、malformedエラー
  • を報告する.
  • sqlite 3バージョン3.8.6
  • データベースファイルサイズ210 MB
  • 位置決めの問題

  • データサイズ
    select count(*) from DataSheet;
    /* */
    950131
    
  • プライマリ・キー
    primary key(ctype,id,DataTime)
    
  • 再現(SQLite Expert)
    select * from DataSheet where id='000537719140' order by DataTime;  /*malformed*/
    select * from DataSheet where ctype=5002 and id='000537719140' order by DataTime; /*OK*/
    
    上記のように、この2つのSQL文の違いはwhere句にoad条件が含まれているかどうかのみであり、なぜそうなるのか、まず次のSQL比較1、2を実行する:
    select * from DataSheet where id='000537719140';  /*OK*/
    select * from DataSheet order by DataTime;     /*malformed,  */
    
  • where句にctype,id,DataTimeがあるときにインデックス(プライマリ・キー)がヒットすると、order by DataTimeが条件を満たすインデックスをソートするため、問題は再現されない
  • .
  • where句がctype,id,DataTimeに完全に一致しない場合、インデックス(プライマリ・キー)がヒットせず、order by DataTimeが条件に合致する結果をソートし、実際に全テーブルスキャンを実行し、問題が再現される
  • .
  • 試験コード:位置決め行
    char * malformed = "select rowid, ctype, id, StartTime, DataTime from DataSheet;"; /*malformed*/
    char * okayQuery = "select rowid, ctype, id, DataTime from DataSheet;"; /*OK*/
    char * sql = okayQuery;
    sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, NULL);
    ncols = sqlite3_column_count(stmt);
    int rowno = 0;
    do {
        rc = sqlite3_step(stmt);
        switch (rc) {
        case SQLITE_ROW:	break;
        case SQLITE_DONE:	rowno = -100;	break;
        default:			fprintf(stderr, "rowno = %d, sqlite3 error %d
    "
    , rowno, rc); break; } if (rowno >= 0) { rowno++; } } while (rowno >= 0); sqlite3_finalize(stmt);
  • sql = okayQueryの場合、950131(rowno:950130)のレコードが照会され、SQLITE_DONE
  • を終了する.
  • sql = malformed、第950300条の記録を取ったときにエラー11 (SQLITE_CORRUPT)を報告する
  • クエリが正常である場合、950131(rowno:950130)レコード
  • のみを巡回できます.
  • 異常照会時、950300(rowno:950301)件のレコードを巡るエラー!


  • 試験コード:位置決め時間
    char * malformed = "select rowid, ctype, id, DataTime, StartTime from DataSheet;";
    char * okayQuery = "select rowid, ctype, id, DataTime from DataSheet;";
    char * sql = malformed;
    sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, NULL);
    ncols = sqlite3_column_count(stmt);
    int rowno = 0;
    do {
      rc = sqlite3_step(stmt);
      switch (rc) {
      case SQLITE_ROW:
        if (rowno >= 950129 && rowno <= 950301/* 950300 */) {
          rowid	 = sqlite3_column_int(stmt, 0);
          ctype  = (char*)sqlite3_column_text(stmt, 1);
          id = (char*)sqlite3_column_text(stmt, 2);
          colltime = (char *)sqlite3_column_text(stmt, 3);
          fprintf(stderr, "rowno: %d, rowid: %i, ctype: %s, id:%s, time:%s
    "
    , rowno, rowid, (ctype?ctype:snull),(id?id:snull), (colltime?colltime:snull)); } break; case SQLITE_DONE: rowno = -100; break; default: fprintf(stderr, "rowno = %d, sqlite3 error %d
    "
    , rowno, rc); break; } if (rowno >= 0) { rowno++; } } while (rowno >= 0); sqlite3_finalize(stmt);
    出力:
    rowno: 950129, rowid: 4478623, ctype: 5002, id:001548532328, time:20191220105300
    rowno: 950130, rowid: 4478624, ctype: 5002, id:001548532328, time:20191220105400
    ...
    rowno: 950297, rowid: 4478791, ctype: 5002, id:001548532342, time:20191220105800
    rowno: 950298, rowid: 4478792, ctype: 5002, id:001548532342, time:20191220105900
    rowno: 950299, rowid: 4478793, ctype: 5002, id:001548532342, time:20191220110100
    rowno = 950300, sqlite3 error 11
    rowno: 950301, rowid: 3526517, ctype: 5002, id:005410401490, time:20191214202200
    
  • ログ#ログ#

  • 20191220.log
    #12-20 11:21:30.098:  [38] 20191220-111700  ...
    #12-20 11:21:30.433:  [39] 20191220-111800  ...
    #12-20 11:21:30.434:  [40] 20191220-111900  ...
    

  • 次の日のデータベースのチェック

  • 2019/12/21のデータベース
  • データベースファイルサイズ:210 MB
  • データベースサイズが同じ
  • Checkメニュー
  • OK


  • ぶんせき

  • 2019/12/20のデータベースにはmalformedの問題がありますが、2019/12/21のデータベースにはこの問題はありません.
  • 原因1:データベースが自動的にリカバリされた
  • データサイクルが到達していない:クリーンアップによる自動リカバリではない
  • 機器に修復機能がない
  • 原因2:データベースコピーの問題
  • 最後のログタイムスタンプ:12-20 11:24:21.057# ...
  • ftpでデータベースをプルし、shellログを保存すると、データベースをプルすると、データベースがトランザクションを実行している可能性があり、問題が発生する


  • 結論

  • ftpデータベースをプルすると、データベースが書き込みデータトランザクションを実行しているため、malformedの問題
  • が発生します.