關於事務開啓與否對數據庫插入數據所需時間的影響的討論

   最近在做sqlite3的二次開發,看到API裏面關於事務的時候,萌生了測試一下事務的開啓與否對插入數據所需要的時間影響的想法,根據sqlite3的api,在後面測試的時候發現對於sqlite3來說事務的開啓與否僅插入1w條數據,時間的差距就已經非常非常明顯了,先說下測試環境:ubuntu12.04, sqlite3 3.7.14.1,測試插入1w條數據。
   
   不開啓事務時的測試代碼如下:
   
 
   intinsert_no_trans()
    {
   
   printf("<--------------------->\n"
          "go intofunction insert_no_trans()\n");

    int j =0;
    for (j = 0;j < 10000; j++)
    {
       sprintf(sql,"INSERT INTO [dev] ([id], [name], [age])\
             values (%d,'%s', %d)", j, "JGood", j);
       if(SQLITE_OK!= sqlite3_exec
             (conn, sql,0, 0, &err_msg))
       {
         fprintf(stderr, "INSERT ERROR: %s\n", err_msg);
         exit(EXIT_FAILURE);
       }
      
    }
   printf("INSERT all succussfully!\n");

   printf("function insert_no_trans() end. \n"
         "<---------------------> \n");

    returnEXIT_SUCCESS;
    }
   


   
   開啓事務的測試代碼如下:

 

   intinsert_with_trans()
    {
   
   printf("<--------------------->\n"
          "go intofunction insert_with_trans()\n");

   sqlite3_exec(conn, "begin;", 0, 0, 0); //開啓事務

    int j =0;
    for (j = 0;j < 10000; j++)
    {
       sprintf(sql,"INSERT INTO [dev] ([id], [name], [age])\
             values (%d,'%s', %d)", j, "JGood", j);
       if(SQLITE_OK!= sqlite3_exec(conn, sql, 0, 0, &err_msg))
       {
          is_succeed =false; //失敗之後把標識設爲false
         fprintf(stderr, "INSERT ERROR: %s\n", err_msg);
          break;
       }
      
    }

   if(is_succeed)
      sqlite3_exec(conn, "commit;", 0, 0, 0); //提交事務
    else
    {
      sqlite3_exec(conn, "rollback;", 0, 0, 0); //回滾事務
      exit(EXIT_FAILURE);
    }

   printf("INSERT all succussfully!\n");

   printf("function insert_with_trans() end. \n"
         "<---------------------> \n");

    returnEXIT_SUCCESS;
    }



   測試結果大跌眼鏡,時間測試我用的是linux的time命令,在開啓了事務的情況下插入1w條數據的時間僅爲0.4s,而在不開啓事務的情況下,由於時間太長,沒有等其執行完,根據.db文件的大小和已經使用的時間推測,假設單位時間插入同樣多條數據,推算出來的時間高達18分鐘。這已經不在一個數量級了,google了一下這個問題,看到網上有人對此是這麼解釋的,如果未啓用事務,sqlite會每插入一條數據,就往磁盤上面寫一次,在整個執行過程中我也觀察到未開啓事務時程序執行期間硬盤燈一直是亮的,這也映證了這一點。而在開啓事務的情況下,其應該是在對數據全部處理完之後才需要執行一次IO操作,時間自然非常快。
   
   
   既然sqlite事務開啓與否對性能影響如此之大,那麼mysql又如何呢?於是繼續測試一下mysql在此種情況下的插入時間的差別。先說明環境,ubuntu10.04,openjdk 1.6.0_24,mysql5.1.66。測試是使用java通過jdbc來操作mysql的,關鍵代碼如下。
   
   未開啓事務(一條一條插入)時測試代碼如下:
    Statementstmt = conn.createStatement();
   conn.setAutoCommit(true);
   stmt.executeUpdate("set autocommit=1");
    for(int i =0; i < 10000; i++)
       stmt.executeUpdate("insert into dev values(1,'java',1);");



   開啓事務時測試代碼如下:
    Statementstmt = conn.createStatement();
   conn.setAutoCommit(false);
   stmt.executeUpdate("set autocommit=0;");
   stmt.executeUpdate("start transaction;");
    for(int i =0; i < 10000; i++)
       stmt.executeUpdate("insert into dev values(1,'java',1);");
   stmt.executeUpdate("commit;");


   
   這個結果也在意料之中,開啓事務之後插入所需要的時間確實比未開啓事務要短,但差距不是很明顯。插入1w條數據時,不開啓事務用時4.4s,開啓事務之後用時2.1s,而插入100w條數據時差距就更明顯了,不開啓事務用時5分44s,開啓之後用時2分10s。同時也觀察了磁盤的讀寫情況,無論事務是否開啓,都沒有出現像sqlite那樣磁盤燈一直亮的情況,唯一的差別就是在程序執行過程中在終端查詢selectcount(*) ,不開啓事務時其值是一直在變化的,開啓事務時多次查詢值均未變化,這也驗證了事務開啓與否在操作上的區別。
   
   再對比一下mysql和sqlite在均插入1w條數據時間的差別,sqlite3用時僅0.4s,mysql用時2.2s,雖然從功能和體積上這二者均不是一個級別的,但是至少可以說明一點,sqlite3的性能非常不錯,甚至在這次的測試中表現出來的插入所需要時間方面比mysql更好(是否可以這樣認爲呢?)。

   最後,需要說明的是,這僅僅只是個人對這二者一次非常簡單的測試,測試方法或者代碼邏輯上如有錯誤,敬請指正。
  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章