數據庫選型之MySQL(普通硬盤)


劉勇   Email:lyssym@sina.comhtml

        本博客記錄做者在工做與研究中所經歷的點滴,一方面給本身的工做與生活留下印記,另外一方面如果能對你們有所幫助,則幸甚至哉矣!java

簡介

        鑑於高頻中心庫task部分(核心業務處理、存儲邏輯)佔用機器較多,爲節省成本,調研數據庫或緩存,以期知足高頻生產的需求:1)峯值1w條/s;2)峯值60w條/m。本着節省成本的角度,本文對開源、免費的數據庫MySQL和PostgreSQL從單一處理和批處理角度展開測試,測試目標平均寫入速率達10000條/s 以上則能知足要求。mysql

 

測試環境

        硬件環境:sql

        10.1.120.37:Intel Pentium, 主頻:2.90G, 內存:6G數據庫

        localhost: Intel Core I5, 主頻:3.10G,  內存:4G緩存

        軟件環境:服務器

        10.1.120.37:Cent OS 6.5,  MySQL 5.6.25 (社區版)網絡

        localhost: Win7,MySQL 5.6.26(社區版)數據結構

      表結構:ide

 1 DROP TABLE IF EXISTS `transaction`;
 2 CREATE TABLE `transaction` (
 3   `tradedate` datetime DEFAULT NULL,
 4   `symbol` varchar(6) DEFAULT NULL,
 5   `symbolname` varchar(8) DEFAULT NULL,
 6   `trdmintime` varchar(6) DEFAULT NULL,
 7   `startprice` decimal(9,3) DEFAULT NULL,
 8   `highprice` decimal(9,3) DEFAULT NULL,
 9   `lowprice` decimal(9,3) DEFAULT NULL,
10   `endprice` decimal(9,3) DEFAULT NULL,
11   `change` decimal(9,3) DEFAULT NULL,
12   `changeratio` decimal(6,3) DEFAULT NULL,
13   `minvolume` decimal(10,0) DEFAULT NULL,
14   `minamout` decimal(16,3) DEFAULT NULL,
15   `unix` bigint(20) DEFAULT NULL,
16   `market` varchar(3) DEFAULT NULL
17 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
table transaction

 

 性能測試

      MySQL測試

        對高頻生產的應用需求,本文構造高頻中心庫系統的數據結構,從單一處理和批處理角度,對遠程節點和本地節點(對比性能所用)MySQL進行寫入操做,分別存儲數據量爲60K、100K、600K條數據,對其速率進行測試。須要指出,因爲常見I/O訪問的瓶頸主要受限於寫入測試,本文只針對寫入操做進行測試,暫不考慮讀取操做或者混合讀寫方式,若寫入操做不知足要求,其它操做無需測試。

        單一處理,即每次處理一條數據,對其性能進行測試,結果見表-1。

表-1 單一處理MySQL測試結果

數據庫IP 數據量(K) 平均寫入速率(條/s)
10.1.120.37 60 1533
10.1.120.37 100 1721
10.1.120.37 600 1772
localhost 60 4889
localhost 100 3875
localhost 600 5057

        從表-1可知:1)隨着處理數據量增長,其寫入速率急劇降低;2)從10.1.120.37和localhost來看,採用單一處理方式,較難知足高頻生產需求。

        批處理方式,分別從批量處理1000、2000、3000條數據出發,對其性能展開測試,結果見表-2。

表-2批處理MySQL測試結果

    1000 2000 3000
數據庫IP 數據量(K) 平均寫入速率(條/s) 平均寫入速率(條/s) 平均寫入速率(條/s)
10.1.120.37 60 1533 1575 1546
10.1.120.37 100 1721 1654 1614
10.1.120.37 600 1772 1710 1725
localhost 60 2236 3033 3654
localhost 100 2252 3589 3936
localhost 600 2289 4717 4759

        從表-2可知:1)增長批處理數據量,遠程節點的寫入速率變化不大,可能受限網絡資源速率;2)採用批處理方式,很難知足高頻生產系統需求,本地節點尚且很難知足,寄但願於遠程節點則更加困難。

      小結

        從上述測試狀況來看,單獨採用MySQL數據庫,實際上是很難知足要求I/O要求,針對60w/m的峯值,即10次/ms,對於普通的物理介質存儲方案(硬盤)來講,該要求是很難知足的。所以,若要考慮物理介質來存儲,固態硬盤是一個選擇方案,具體有待於測試。

        PostgreSQL測試

        因爲PostgreSQL能夠徹底勝任任何中上規模的範圍內的業務,所以,本文也針對PostgreSQL是否知足高頻生產的應用需求展開性能測試。目前只針對本地節點從單一處理和批處理出發,分別存儲上述數據量(見MySQL測試),若本地節點很難知足需求,遠程節點也無需測試了。

        每次處理一條數據,結果見表-3。

表-3單一處理PostgreSQL測試結果

數據庫IP 數據量(K) 平均寫入速率(條/s)
localhost 60 2055
localhost 100 2303
localhost 600 2102

 

        分別從批量處理1000、2000、3000條數據出發,對其性能展開測試,結果見表-4。

表-4單一處理PostgreSQL測試結果

    1000 2000 3000
數據庫IP 數據量(K) 平均寫入速率(條/s) 平均寫入速率(條/s) 平均寫入速率(條/s)
localhost 60 2167 1755 2342
localhost 100 2200 2436 1423
localhost 600 1952 2184 2201

      小結

        從上述測試結果來看,PostgreSQL針對本文目標應用場景的需求,差距甚遠。本地節點尚且沒法勝任需求,同時其CPU的處理能力也較遠程節點強一些,所以再也不對遠程節點展開測試。

 

總結

        經上述測試,PostgreSQL相對MySQL的寫入速率稍微緩慢一些。針對節省成本的考慮,擬採用單一服務器來知足應用需求,難度巨大,主要集中於,針對60w/m的峯值,即10次/ms,對於普通的物理介質存儲方案(機械硬盤)來講,該I/O要求是很難知足的。所以,若要考慮物理介質來存儲,固態硬盤是一個選擇方案,具體有待於測試。

 

附錄

測試程序核心源代碼:

  1 import java.sql.Date;
  2 import java.math.BigDecimal;
  3 
  4 public class Transaction {
  5     private Date tradedate; 
  6     private String symbol;
  7     private String symbolName;
  8     private String trdmintime;
  9     private BigDecimal startprice;
 10     private BigDecimal highprice;
 11     private BigDecimal lowprice;
 12     private BigDecimal endprice;
 13     private BigDecimal change;
 14     private BigDecimal changeratio;
 15     private BigDecimal minvolume;
 16     private BigDecimal minamout;
 17     private long unix;
 18     private String market;
 19     
 20     public Transaction(Date tradedate,
 21                         String symbol,
 22                         String symbolName,
 23                         String trdmintime,
 24                         BigDecimal startprice,
 25                         BigDecimal highprice,
 26                         BigDecimal lowprice,
 27                         BigDecimal endprice,
 28                         BigDecimal change,
 29                         BigDecimal changeratio,
 30                         BigDecimal minvolume,
 31                         BigDecimal minamout,
 32                         long unix,
 33                         String market)
 34     {
 35         this.symbol = symbol;
 36         this.symbolName = symbolName;
 37         this.trdmintime = trdmintime;
 38         this.startprice = startprice;
 39         this.highprice = highprice;
 40         this.lowprice = lowprice;
 41         this.endprice = endprice;
 42         this.change = change;
 43         this.changeratio = changeratio;
 44         this.minvolume = minvolume;
 45         this.minamout = minamout;
 46         this.unix = unix;
 47         this.market = market;
 48     }
 49 
 50     public void setTradedate(Date tradedate) {
 51         this.tradedate = tradedate;
 52     }
 53 
 54     public void setSymbol(String symbol) {
 55         this.symbol = symbol;
 56     }
 57 
 58     public void setSymbolName(String symbolName) {
 59         this.symbolName = symbolName;
 60     }
 61 
 62     public void setTrdmintime(String trdmintime) {
 63         this.trdmintime = trdmintime;
 64     }
 65 
 66     public void setStartprice(BigDecimal startprice) {
 67         this.startprice = startprice;
 68     }
 69 
 70     public void setHighprice(BigDecimal highprice) {
 71         this.highprice = highprice;
 72     }
 73 
 74     public void setLowprice(BigDecimal lowprice) {
 75         this.lowprice = lowprice;
 76     }
 77 
 78     public void setEndprice(BigDecimal endprice) {
 79         this.endprice = endprice;
 80     }
 81 
 82     public void setChange(BigDecimal change) {
 83         this.change = change;
 84     }
 85 
 86     public void setChangeratio(BigDecimal changeratio) {
 87         this.changeratio = changeratio;
 88     }
 89 
 90     public void setMinvolume(BigDecimal minvolume) {
 91         this.minvolume = minvolume;
 92     }
 93 
 94     public void setMinamout(BigDecimal minamout) {
 95         this.minamout = minamout;
 96     }
 97 
 98     public void setUnix(long unix) {
 99         this.unix = unix;
100     }
101 
102     public void setMarket(String market) {
103         this.market = market;
104     }
105 
106     public Date getTradedate() {
107         return tradedate;
108     }
109 
110     public String getSymbol() {
111         return symbol;
112     }
113 
114     public String getSymbolName() {
115         return symbolName;
116     }
117 
118     public String getTrdmintime() {
119         return trdmintime;
120     }
121 
122     public BigDecimal getStartprice() {
123         return startprice;
124     }
125 
126     public BigDecimal getHighprice() {
127         return highprice;
128     }
129 
130     public BigDecimal getLowprice() {
131         return lowprice;
132     }
133 
134     public BigDecimal getEndprice() {
135         return endprice;
136     }
137 
138     public BigDecimal getChange() {
139         return change;
140     }
141 
142     public BigDecimal getChangeratio() {
143         return changeratio;
144     }
145 
146     public BigDecimal getMinvolume() {
147         return minvolume;
148     }
149 
150     public BigDecimal getMinamout() {
151         return minamout;
152     }
153 
154     public long getUnix() {
155         return unix;
156     }
157 
158     public String getMarket() {
159         return market;
160     }
161 
162 }
Class Transaction
  1 import java.sql.*;
  2 import java.math.BigDecimal;
  3 import java.math.RoundingMode;
  4 
  5 public class Test {
  6     public static int PREFIX = 1000;        // 批處理量
  7     public static int FIX = 600;            // 操做數據 K
  8     private Connection conn;
  9     private PreparedStatement pstm;
 10     private String sql;
 11     private int count;
 12     
 13     public static void main(String[] args) {
 14         // TODO Auto-generated method stub
 15         
 16         Transaction ts = new Transaction(null,
 17                                         "",
 18                                         "",
 19                                         "010000",
 20                                         new BigDecimal(15.857).setScale(3, RoundingMode.HALF_UP),
 21                                         new BigDecimal(18.550).setScale(3, RoundingMode.HALF_UP),
 22                                         new BigDecimal(13.147).setScale(3, RoundingMode.HALF_UP),
 23                                         new BigDecimal(16.383).setScale(3, RoundingMode.HALF_UP),
 24                                         new BigDecimal(0.151).setScale(3, RoundingMode.HALF_UP),
 25                                         new BigDecimal(1.550).setScale(3, RoundingMode.HALF_UP),
 26                                         new BigDecimal(5000000).setScale(3, RoundingMode.HALF_UP),
 27                                         new BigDecimal(500000000).setScale(3, RoundingMode.HALF_UP),
 28                                         System.currentTimeMillis(),
 29                                         "SSE");
 30         
 31         Test test = new Test();
 32         int symbolData = 100000;
 33         test.initMySQL();
 34         
 35         long start = test.getRunTime();
 36         for(int i = 0; i < Test.FIX*1000; i++) {
 37             ts.setTradedate(new Date(System.currentTimeMillis()));
 38             ts.setSymbol(Integer.toString(symbolData));
 39             symbolData++ ;
 40             ts.setSymbolName("中國銀行");
 41             ts.setUnix(ts.getUnix()+1);
 42             test.insertData(ts);
 43         }
 44         long end = test.getRunTime();
 45         System.out.println("寫入速率爲: " + Test.FIX*1000*1000/(end-start));
 46         
 47         test.down();
 48     }
 49     
 50     
 51     public void initMySQL()
 52     {
 53         String driver = "com.mysql.jdbc.Driver";
 54         String url = "jdbc:mysql://10.1.120.37:3306/hdfs";
 55         String user = "root";
 56         String password = "";
 57         
 58         try {
 59             Class.forName(driver);
 60             conn = DriverManager.getConnection(url, user, password);
 61             if (!conn.isClosed())
 62                 System.out.println("Start MySQL!");
 63         } catch (Exception e) {
 64             e.printStackTrace();
 65         }
 66         
 67         count = 0;
 68         sql = "insert into transaction" + " values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
 69         try {
 70             pstm = conn.prepareStatement(sql);
 71             conn.setAutoCommit(false);
 72         } catch (SQLException e) {
 73             e.printStackTrace();
 74         }
 75     }
 76     
 77     
 78     public void insertData(Transaction ts)
 79     {
 80         try {
 81             pstm.setDate(1, ts.getTradedate());
 82             pstm.setString(2,  ts.getSymbol());
 83             pstm.setString(3, ts.getSymbolName());
 84             pstm.setString(4, ts.getTrdmintime());
 85             pstm.setBigDecimal(5, ts.getStartprice());
 86             pstm.setBigDecimal(6, ts.getHighprice());
 87             pstm.setBigDecimal(7, ts.getLowprice());
 88             pstm.setBigDecimal(8, ts.getEndprice());
 89             pstm.setBigDecimal(9, ts.getChange());
 90             pstm.setBigDecimal(10, ts.getChangeratio());
 91             pstm.setBigDecimal(11, ts.getMinvolume());
 92             pstm.setBigDecimal(12, ts.getMinamout());
 93             pstm.setLong(13, ts.getUnix());
 94             pstm.setString(14, ts.getMarket());
 95     
 96             pstm.executeUpdate();
 97             count++;
 98             if (count == Test.PREFIX) {
 99                 conn.commit();
100                 conn.setAutoCommit(false);
101                 count = 0;
102             }
103                         
104         } catch (SQLException e) {
105             try {
106                 conn.rollback();
107             } catch (SQLException e1) {
108                 // TODO Auto-generated catch block
109                 e1.printStackTrace();
110             }
111             e.printStackTrace();
112         }
113     }
114     
115     
116     public long getRunTime()
117     {
118         return System.currentTimeMillis();
119     }
120     
121     
122     public void down()
123     {
124         try {
125             if (!conn.isClosed()) {
126                 conn.close();
127                 System.out.println("Close MySQL!");
128             }
129         } catch (Exception e) {
130             e.printStackTrace();
131         }
132     }
133 
134 }
Class Test

 


  做者:志青雲集
  出處:http://www.cnblogs.com/lyssym/p/4821490.html  若是,您認爲閱讀這篇博客讓您有些收穫,不妨點擊一下右下角的【推薦】。  若是,您但願更容易地發現個人新博客,不妨點擊一下左下角的【關注我】。  若是,您對個人博客所講述的內容有興趣,請繼續關注個人後續博客,我是【志青雲集】。  本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。

相關文章
相關標籤/搜索