<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    經驗不在于年限,在于積累---專注互聯網軟件開發

    把工作當事業做,把項目當作品做!

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      55 Posts :: 0 Stories :: 66 Comments :: 0 Trackbacks
    在數據庫的相關開發中,經常會遇到數據的批量插入問題。本文主要是通過實驗的方式探討批量數據插入的瓶頸,以及優化建議。


    10w條記錄的插入作為實驗對象,采用下面的幾種方法插入:

    1.       普通插入:普通的一條條插入

    2.       普通插入+手動提交:setAutoCommit(false)、commit()

    3.       普通插入+手動提交+ prepareStatement方式

    4.       批量插入:addBatchexecuteBatch

    5.       批量插入:insert into tableName (x,xx,xxx) values(x,xx,xxx),(xx,xxx,xxxx)…,

    6.       多線程插入。

    7.       InnoDB引擎和MyISAM引擎的比較。


    實驗環境:

    數據庫:MySQL 5.0

    機器硬件:

    內存 3G 

    CPU AMD雙核4400+ 2.3G

    首先建立一個簡單的user表:

    CREATE TABLE `user` (                                         

              `id` varchar(50) NOT NULL,                                  

              `seqid` bigint(20) NOT NULL auto_increment,                 

              `name` varchar(50) NOT NULL,                                 

              PRIMARY KEY (`seqid`)

            ) ENGINE=MyISAM DEFAULT CHARSET=utf8

    一、普通插入
    代碼:

     1Connection conn=source.getConnection();
     2Statement s=conn.createStatement();
     3String sql="";
     4long start=System.currentTimeMillis();
     5for(int i=0;i<100000;i++)
     6{
     7    sql="insert into user(id,name) value('"+(i+1)+"','chenxinhan')";
     8    s.execute(sql);
     9}

    10s.close();
    11conn.close();
    12long end=System.currentTimeMillis();
    13System.out.println("commonInsert()執行時間為:"+(end-start)+"ms");
    輸出結果:
    commonInsert()執行時間為:13828ms

    二、普通插入+手動提交:setAutoCommit(false)、commit()
    代碼:
     1Connection conn=source.getConnection();
     2conn.setAutoCommit(false);
     3Statement s=conn.createStatement();
     4String sql="";
     5long start=System.currentTimeMillis();
     6for(int i=0;i<100000;i++)
     7{
     8   sql="insert into user(id,name) value('"+(i+1)+"','chenxinhan')";
     9   s.execute(sql);
    10}

    11conn.commit();
    12s.close();
    13conn.close();
    14long end=System.currentTimeMillis();
    15System.out.println("commonInsert()執行時間為:"+(end-start)+"ms");
    輸出結果:
    commonInsert()執行時間為:13813ms
    對比分析:
    可以看出,僅僅是這種方式的設置,對性能的影響并不大。

    三、普通插入+手動提交+ prepareStatement方式
    代碼:
     1Connection conn=source.getConnection();
     2        conn.setAutoCommit(false);
     3        PreparedStatement ps=conn.prepareStatement("insert into user(id,name) value(?,?)");
     4        long start=System.currentTimeMillis();
     5        for(int i=0;i<100000;i++)
     6        {
     7            ps.setString(1,(i+1)+"");
     8            ps.setString(2,"chenxinhan");
     9            ps.execute();
    10        }

    11        conn.commit();
    12        ps.close();
    13        conn.close();
    14        long end=System.currentTimeMillis();
    15        System.out.println("prepareStatementInsert()執行時間為:"+(end-start)+"ms");
    輸出結果:
    prepareStatementInsert()執行時間為:12797ms
    對比分析:
    采用prepareStatement的方式確實可以提高一點性能,因為減少了數據庫引擎解析優化SQL語句的時間,但是由于現在的插入語句太簡單,所以性能提升不明顯。

    四、批量插入:addBatchexecuteBatch
    代碼:
     1        Connection conn=source.getConnection();
     2        conn.setAutoCommit(false);
     3        Statement s=conn.createStatement();
     4        String sql="";
     5        long start=System.currentTimeMillis();
     6        for(int j=0;j<100;j++)
     7        {
     8            for(int i=0;i<1000;i++)
     9            {
    10                sql="insert into user(id,name) value('"+(i+1)+"','chenxinhan')";
    11                s.addBatch(sql);
    12            }

    13            s.executeBatch();
    14            conn.commit();
    15            s.clearBatch();
    16        }

    17        s.close();
    18        conn.close();
    19        long end=System.currentTimeMillis();
    20        System.out.println("batchInsert()執行時間為:"+(end-start)+"ms");
    輸出結果:
    batchInsert()執行時間為:13625ms
    對比分析:
    按道理,這種批處理的方式是要快些的,但是測試結果卻不盡人意,有點不解,請高人拍磚。

    五、批量插入:insert into tableName (x,xx,xxx) values(x,xx,xxx),(xx,xxx,xxxx)…,
    代碼:
     1Connection conn=source.getConnection();
     2        conn.setAutoCommit(false);
     3        Statement s=conn.createStatement();
     4        StringBuilder sql=new StringBuilder("");
     5        long start=System.currentTimeMillis();
     6        for(int j=0;j<100;j++)
     7        {
     8            sql=new StringBuilder("");
     9            sql.append("insert into user(id,name) values ");
    10            for(int i=0;i<1000;i++)
    11            {
    12                if(i==999)
    13                    sql.append("('").append(i+1).append("',").append("'cxh')");
    14                else
    15                    sql.append("('").append(i+1).append("',").append("'cxh'),");
    16            }

    17            s.execute(sql.toString());
    18            conn.commit();
    19        }

    20        s.close();
    21        conn.close();
    22        long end=System.currentTimeMillis();
    23        System.out.println("manyInsert()執行時間為:"+(end-start)+"ms");
    輸出結果:
    manyInsert()執行時間為:937ms
    對比分析:
    發現采用這種方式的批量插入性能提升最明顯,有10倍以上的性能提升。所以這種方式是我推薦的批量插入方式!

    六、多線程插入
    在第五種方式的基礎上采用多線程插入。
    代碼:
     1final Connection conn=source.getConnection();
     2        for(int j=0;j<3;j++)
     3        {
     4            Thread t=new Thread(){
     5                @Override
     6                public void run() {
     7                    try
     8                    {
     9                        long start=System.currentTimeMillis();
    10                        Statement s=conn.createStatement();
    11                        StringBuilder sql=new StringBuilder("");
    12                        for(int j=0;j<100;j++)
    13                        {
    14                            conn.setAutoCommit(false);
    15                            sql=new StringBuilder("");
    16                            sql.append("insert into user (id,name) values ");
    17                            for(int i=0;i<1000;i++)
    18                            {
    19                                if(i==999)
    20                                    sql.append("('").append(i+1).append("',").append("'cxh')");
    21                                else
    22                                    sql.append("('").append(i+1).append("',").append("'cxh'),");
    23                            }

    24                            s.execute(sql.toString());
    25                            conn.commit();
    26                        }

    27                        s.close();
    28                        long end=System.currentTimeMillis();
    29                        System.out.println("multiThreadBatchInsert()執行時間為:"+(end-start)+"ms");
    30                    }

    31                    catch(Exception e)
    32                    {
    33                        e.printStackTrace();
    34                    }

    35                }

    36            }
    ;
    37            t.start();
    38            //t.join();
    39        }
    輸出結果:
    multiThreadBatchInsert()執行時間為:2437ms
    multiThreadBatchInsert()執行時間為:2625ms
    multiThreadBatchInsert()執行時間為:2703ms

    注意:上面我采用的是三個線程插入30w條數據。
    取最大時間為2703ms,較上面的937ms,基本還是三倍的時間。
    所以發現此時多線程也解決不了批量數據插入問題。原因就是,這時候的性能瓶頸不是CPU,而是數據庫!

    七、InnoDB引擎和MyISAM引擎的比較
    最后,分析一下,這兩個引擎對批量數據插入的影響。
    先建立user2數據表:

    CREATE TABLE `user2` (                                         

              `id` varchar(50) NOT NULL,                                  

              `seqid` bigint(20) NOT NULL auto_increment,                 

              `name` varchar(50) NOT NULL,                                 

              PRIMARY KEY (`seqid`)

            ) ENGINE=InnoDB DEFAULT CHARSET=utf8

    代碼:
     1Connection conn=source.getConnection();
     2        conn.setAutoCommit(false);
     3        Statement s=conn.createStatement();
     4        StringBuilder sql=new StringBuilder("");
     5        long start=System.currentTimeMillis();
     6        for(int j=0;j<100;j++)
     7        {
     8            sql=new StringBuilder("");
     9            sql.append("insert into user2 (id,name) values ");
    10            for(int i=0;i<1000;i++)
    11            {
    12                if(i==999)
    13                    sql.append("('").append(i+1).append("',").append("'cxh')");
    14                else
    15                    sql.append("('").append(i+1).append("',").append("'cxh'),");
    16            }

    17            s.execute(sql.toString());
    18            conn.commit();
    19        }

    20        s.close();
    21        conn.close();
    22        long end=System.currentTimeMillis();
    23        System.out.println("manyInsert2()執行時間為:"+(end-start)+"ms");
    輸出結果:
    manyInsert2()執行時間為:3484ms
    注意:第七項的代碼和第五是一樣的,除了數據表名稱不同(user、user2)
    但是,
    InnoDB :3484ms
    MyISAM:937ms
    所以,MyISAM引擎對大數據量的插入性能較好。

    總結:
    對于大數據量的插入,建議使用insert into tableName (x,xx,xxx) values(x,xx,xxx),(xx,xxx,xxxx)…,的方式,引擎建議使用MyISAM引擎
    友情提醒:本博文章歡迎轉載,但請注明出處:陳新漢


    posted on 2009-09-01 12:57 hankchen 閱讀(8133) 評論(5)  編輯  收藏 所屬分類: SQL+MySQL

    Feedback

    # re: 數據庫批量數據插入問題分析 2009-09-01 13:30 hah
    多線程沒用,數據庫以此只能執行一條命令,除非多個connection  回復  更多評論
      

    # re: 數據庫批量數據插入問題分析[未登錄] 2009-09-01 14:13 Bobby
    可惜的是MyISAM不支持事務處理  回復  更多評論
      

    # re: 數據庫批量數據插入問題分析 2009-09-01 19:55 vagrant
    你推薦的這種,語法是mysql特有的吧,有沒有其他數據庫的性能比較?  回復  更多評論
      

    # re: 數據庫批量數據插入問題分析 2009-09-01 20:38 陳新漢
    @hah
    其實,多個connection也沒用,因為瓶頸是數據庫的鎖機制。  回復  更多評論
      

    # re: 數據庫批量數據插入問題分析 2009-09-02 09:00 guest
    試試preparedstatement的batch insert?
      回復  更多評論
      

    主站蜘蛛池模板: 国产亚洲成AV人片在线观黄桃| 亚洲精品中文字幕无乱码| 免费毛片在线看不用播放器| 亚洲网址在线观看你懂的| 91免费精品国自产拍在线不卡| MM1313亚洲精品无码久久| 亚洲中文字幕在线第六区| 久久综合给合久久国产免费| 亚洲啪AV永久无码精品放毛片| 国产亚洲情侣一区二区无| 亚洲三级在线免费观看| 少妇亚洲免费精品| 亚洲天天在线日亚洲洲精| 日韩一区二区三区免费体验| 99re6在线视频精品免费| 激情五月亚洲色图| 国产亚洲精品精品国产亚洲综合 | 黄色免费网址在线观看| 久久久久久亚洲精品中文字幕| 午夜免费福利在线观看| 好紧我太爽了视频免费国产| 亚洲色欲色欱wwW在线| 国产成人亚洲精品青草天美 | 久久亚洲中文字幕精品有坂深雪| 精品剧情v国产在免费线观看| 搡女人免费免费视频观看| 亚洲国产精品网站在线播放| 亚洲AV无码一区二区二三区软件| 日韩免费在线观看| 久久久久高潮毛片免费全部播放 | 亚洲尹人香蕉网在线视颅| 国产午夜免费福利红片| 18禁男女爽爽爽午夜网站免费| 久久av免费天堂小草播放| 亚洲中文无码永久免| 精品亚洲aⅴ在线观看| 亚洲中文字幕无码爆乳AV| 国产免费观看网站| 我想看一级毛片免费的| 亚洲一级毛片免费看| 久久久久成人精品免费播放动漫|