<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无码网址| 久久精品国产亚洲一区二区三区| 亚洲成a人片在线不卡一二三区| 日产国产精品亚洲系列| 成人免费777777被爆出| 亚洲人成高清在线播放| 午夜亚洲av永久无码精品 | 99免费在线观看视频| 亚洲中文无码永久免费| 亚洲国产无套无码av电影| 美女裸身网站免费看免费网站| 九九免费精品视频在这里| 亚洲日产2021三区| 精品亚洲视频在线观看| 一个人免费观看视频www| 国产成人1024精品免费| 亚洲国产系列一区二区三区| 亚洲精品国偷自产在线| 免费看片A级毛片免费看| 四虎国产精品永久免费网址| 免费看一级一级人妻片 | 中文字幕亚洲男人的天堂网络| 爱情岛论坛网亚洲品质自拍| 99视频在线精品免费观看6| 在线免费视频你懂的| 亚洲国产精品无码久久98| 久久精品a亚洲国产v高清不卡| 国产av无码专区亚洲国产精品| 天天拍拍天天爽免费视频 | 亚洲日韩精品一区二区三区无码 | 亚洲人成色7777在线观看不卡| 青青青国产在线观看免费网站| 中文字幕免费不卡二区| 另类小说亚洲色图| 亚洲天堂男人影院| 老司机亚洲精品影院| 亚洲高清国产拍精品26U| 亚洲精品无码AV中文字幕电影网站| 成人性生交大片免费看午夜a| 99国产精品免费视频观看| 一级毛片成人免费看a|