【问题标题】:Creating temporary table while still accessing other tables在访问其他表的同时创建临时表
【发布时间】:2015-06-20 07:48:03
【问题描述】:

我有 2 个或更多数据库附加到一个 SQLite 数据库连接。每个数据库由 3 个表组成。为了更好地进行搜索/过滤,我在所有表和数据库上创建了一个巨大的临时表,如下所示:

"CREATE TEMPORARY TABLE temp_table AS "
   "SELECT * FROM pb.name_table " 
      "LEFT JOIN pb.phone_table ON (pb.name_table.id=pb.phone_table.id) " \
      "LEFT JOIN pb.email_table ON (pb.name_table.id=pb.email_table.id) " \
   "UNION SELECT * FROM name_table " \<br>
      "LEFT JOIN phone_table ON (name_table.id=phone_table.id) " \
      "LEFT JOIN email_table ON (name_table.id=email_table.id);";

如果表发生变化,我必须重新创建临时表。
随着数据量的增加,创建临时表需要一些时间,但由于我可以连续读取该表,我的思路如下:

  1. 创建一个线程,在后台创建第二个临时表
  2. 阻止读取客户端的访问
  3. 删除第一个临时表
  4. 重命名第二个临时表

现在的问题是:创建临时表是对数据库的写访问,它也会自动阻塞所有读取线程。

有谁知道我该如何处理这个问题?我在重新创建临时表时需要读取权限。

【问题讨论】:

    标签: c++ sqlite temp-tables


    【解决方案1】:

    只要所有线程都属于同一程序,您就可以控制所有数据库连接。 所以你可以把数据写在一个完全独立的数据库里,ATTACH 很快。

    【讨论】:

      【解决方案2】:

      非常感谢您的回答。我改变了我的代码,发现我需要在工作线程中建立一个新的数据库连接(sqlite3_open)来不阻塞另一个线程。在附加的“临时数据库”中创建临时表也是不可能的,因为创建临时表不允许使用限定符(如:x.temp_table),所以我必须创建一个消耗大量内存的真实表我们的闪存文件系统(这是不允许的)。
      可是等等!我有个主意
      (2 小时后)
      我做的!我打开一个空数据库并将所有相关数据库附加到连接。我在空数据库“中”创建了一个临时表,它不消耗闪存中的内存,因为它是临时的。
      当我必须创建一个新表时,我打开另一个空数据库并将相关数据库附加到连接。操作完成后,我切换旧连接和新连接。代码如下:

          #include <iostream>
          #include "dbAccess.h"
          #include <cstdio>
          #include <string>
          #include <cstring>
      
          using namespace std;
      
          bool inProgress = true;
      
          DWORD WINAPI createTempTableThread(void *param);
      
          int callback(void *NotUsed, int argc, char **argv, char **azColName)
          {
              cout << "*";
              return 0;
          }
      
          int main(void)
          {
              sqlite3* db = NULL;
              HANDLE hThreadHandle = NULL;
              CdbAccess *dba = new CdbAccess();
              int i = 0;
              db = dba->dbaConnect();
              dba->dbaSetDatabase(db);
      
              cout << "INFO: Creating initial temporary table. " << endl;
              sqlite3_exec(dba->dbaGetDatabase(), "CREATE TEMPORARY TABLE temp_table AS " \
                         "SELECT * FROM pb.name_table " \
                            "LEFT JOIN pb.phone_table ON (pb.name_table.id=pb.phone_table.id) " \
                            "LEFT JOIN pb.email_table ON (pb.name_table.id=pb.email_table.id) " \
                         "UNION SELECT * FROM intern.name_table " \
                            "LEFT JOIN intern.phone_table ON (intern.name_table.id=intern.phone_table.id) " \
                            "LEFT JOIN intern.email_table ON (intern.name_table.id=email_intern.table.id);", NULL, NULL, NULL);
              cout << "INFO: Creating initial temporary table finished. " << endl;
      
              while(1)
              {
                  hThreadHandle = CreateThread(0, 0, createTempTableThread, dba, 0, 0);
      
                  while(inProgress)
                  {
                  sqlite3_exec(dba->dbaGetDatabase(), "SELECT * FROM name_table WHERE id LIKE 1;", callback, NULL, NULL);
                  }
      
                  for(i = 0; i < 5; i++)
                  {
                      sqlite3_exec(dba->dbaGetDatabase(), "SELECT * FROM name_table WHERE id LIKE 2;", callback, NULL, NULL);
                  }
      
                  inProgress = true;
      
                  CloseHandle(hThreadHandle);
              }
      
      
              dba->dbaDisconnect();
      
              return 0;
          }
      
      
      CdbAccess::CdbAccess()
      {
          hSemaphore = CreateSemaphore(NULL, 1, 1, 0);
      }
      
      CdbAccess::~CdbAccess()
      {
      }
      
      sqlite3 *CdbAccess::dbaConnect()
      {
          sqlite3 *db;
          static int num = 1;
          int err = SQLITE_OK;
          string attach = "ATTACH DATABASE \"";
          string internal = "cbInternal.db";
      
          if(num == 1)
          {
              cout << endl << "INFO: cbTemp1.db";
              err = sqlite3_open("cbTemp1.db", &db);
              num = 2;
          }
          else
          {
              cout << endl << "INFO: cbTemp2.db";
              err = sqlite3_open("cbTemp2.db", &db);
              num = 1;
          }
      
          if(err == SQLITE_OK)
          {
              cout << endl << "INFO: Temp database opened.";
              err = sqlite3_exec(db, "ATTACH DATABASE \"cbInternal.db\" AS intern;", NULL, NULL, NULL);
              if(err == SQLITE_OK)
              {
                  cout << endl << "INFO: Internal database attached.";
      
                  err = sqlite3_exec(db, "ATTACH DATABASE \"0123456789.db\" AS pb;", NULL, NULL, NULL);
                  if(err == SQLITE_OK)
                  {
                      cout << endl << "INFO: Phone book attached.";
                  }
                  else
                  {
                      cout << endl << "ERROR: Attaching phone book: " << sqlite3_errmsg(db);
                  }
              }
              else
              {
                  cout << endl << "ERROR: Attaching internal database: " << sqlite3_errmsg(db);
              }
          }
          else
          {
              cout << endl << "ERROR: Opening database: " << sqlite3_errmsg(db);
          }
      
          return db;
      }
      
      int CdbAccess::dbaDisconnect(void)
      {
          int err = SQLITE_OK;
      
          err = sqlite3_exec(db, "DETACH DATABASE pb;", NULL, NULL, NULL);
          if(err == SQLITE_OK)
          {
              cout << endl << "INFO: Phone book detached.";
              err = sqlite3_exec(db, "DETACH DATABASE intern;", NULL, NULL, NULL);
              if(err == SQLITE_OK)
              {
                  cout << endl << "INFO: Internal database detached.";
                  err = sqlite3_close(db);
                  if(err == SQLITE_OK)
                  {
                      cout << endl << "INFO: Database connection closed.";
                  }
                  else
                  {
                      cout << endl << "ERROR: Could not close database: " << sqlite3_errmsg(db);
                  }
              }
              else
              {
                  cout << endl << "ERROR: Could not detach internal database: " << sqlite3_errmsg(db);
              }
          }
          else
          {
              cout << endl << "ERROR: Could not detach phone book: " << sqlite3_errmsg(db);
          }
      
          return err;
      }
      
      sqlite3* CdbAccess::dbaGetDatabase(void)
      {
          return db;
      }
      
      void CdbAccess::dbaSetDatabase(sqlite3 * sqldb)
      {
          db = sqldb;
      }
      
      int CdbAccess::dbaGetTempTableAccess(void)
      {
          cout << endl << "INFO: Access requested.";
          WaitForSingleObject(hSemaphore, INFINITE);
          return 0;
      }
      
      int CdbAccess::dbaReleaseTempTableAccess(void)
      {
          cout << endl << "INFO: Access released.";
          ReleaseSemaphore(hSemaphore, 1, NULL);
          return 0;
      }
      
      
      DWORD WINAPI createTempTableThread(void *param)
      {
          int err = SQLITE_OK;
          CdbAccess *d = (CdbAccess *)param;
          sqlite3 *db;
      
          cout << endl << "INFO: createTempTable: IN";
      
          inProgress = true; // global variable for test porpose only
      
          db = d->dbaConnect();
      
          if(db != NULL)
          {
              cout << endl << "Thread: INFO: Creating temporary table. ";
              err = sqlite3_exec(db, "CREATE TEMPORARY TABLE temp_table AS " \
                         "SELECT * FROM pb.name_table " \
                            "LEFT JOIN pb.phone_table ON (pb.name_table.id=pb.phone_table.id) " \
                            "LEFT JOIN pb.email_table ON (pb.name_table.id=pb.email_table.id) " \
                         "UNION SELECT * FROM intern.name_table " \
                            "LEFT JOIN intern.phone_table ON (intern.name_table.id=intern.phone_table.id) " \
                            "LEFT JOIN intern.email_table ON (intern.name_table.id=intern.email_table.id);", NULL, NULL, NULL);
          }
      
          if(err != SQLITE_OK)
          {
              cout << endl << "Thread: ERROR: Creating temporary table: " << sqlite3_errmsg(db);
          }
          else
          {
              cout << endl << "Thread: INFO: Creating temporary table finished. ";
          }
      
          d->dbaSetDatabase(db);
      
          inProgress = false; // global variable for test porpose only
      
          cout << endl << "Thread: INFO: createTempTable: OUT";
      
          return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-03-06
        • 1970-01-01
        • 1970-01-01
        • 2019-09-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多