很多同學一直抱怨手頭木有一個真實的數據庫,無法進行數據庫性能試驗,CSDN得知了同學們的苦惱,立刻開放了部分數據庫,供同學們學習、參考,對CSDN這種大公無私、舍己為人的行為,有關部門對此進行了高度的贊揚,下面就帶領同學們來進行一個小小的性能對比測試。
實驗選擇了三個數據庫:Oracle11g、MySQL5.1以及DM7。Oracle作為商業數據庫大哥大的代表,MySQL作為開源數據庫的代表,DM7很多同學估計就不清楚了(達夢數據庫),暫時作為國產數據庫的代表吧(同學們輕拍^_^)。
測試環境
OS | WINDOWS XP SP3 |
CPU | Intel i3 530 @2.93GHz |
MEMORY | 4G |
ORACLE | 11.1.0.6.0 |
MySQL | 5.1.30 |
DM | V7 |
導入數據庫性能測試
這次CSDN泄漏的密碼庫規模說大不大,說小不小,600多萬行(CSDN的用戶數霸氣外漏,博客園有多少呢?),同學們測試的福音啊。還好我第一時間download了,CSDN的處理還是比較迅速的,很快網上的下載鏈接就失效了,贊一個。這個密碼庫是一個文本文件,200多M,用UE打開還要等一會...每行的格式如下:
用戶名 # 密碼 # 郵箱
三個字段間的間隔是’空格#空格’,為了方便導入數據庫,我們使用UE將其分割符全部替換為#。
腫么導入數據庫呢?上面選的三個數據庫都具有快速導入的工具,Oralce提供了sqlldr工具,MySQL提供了load data命令,DM7提供了dmfldr工具,dmfldr和sqlldr工具感覺使用起來比較相似,MySQL提供的load data作為一種SQL命令。
建表
導入之前我們需要創建一個空表,Oracle和DM7的建表語句如下:
CREATE TABLE CSDN(ID VARCHAR(256), PWD VARCHAR(256), EMAIL VARCHAR(256));
MySQL的建表語句我們指定存儲引擎為INNODB:
CREATE TABLE CSDN(ID VARCHAR(256), PWD VARCHAR(256), EMAIL VARCHAR(256)) ENGINE=INNODB;
初始建表語句這里不指定任何索引。
裝載數據
ORACLE
首先創建控制文件ora_csdn.ctrl,內容如下:
UNRECOVERABLE LOAD DATA INFILE 'D:\CSDN\www.csdn.net.sql' INSERT into table CSDN fields terminated by '#' ( ID, PWD, EMAIL )
然后使用sqlldr工具:
sqlldr userid=SYSMAN/SYSDBA control=D:/CSDN/ora_csdn.ctrl DIRECT=TRUE log=resulthis.out
輸出文件為resulthis.out:
SQL*Loader: Release 11.1.0.6.0 - Production on 星期六 12月 24 16:01:06 2011 Copyright (c) 1982, 2007, Oracle. All rights reserved. 控制文件: D:/CSDN/ora_csdn.ctrl 數據文件: D:\CSDN\www.csdn.net.sql 錯誤文件: D:/CSDN/www.csdn.net.bad 廢棄文件: 未作指定 (可廢棄所有記錄) 要加載的數: ALL 要跳過的數: 0 允許的錯誤: 50 繼續: 未作指定 所用路徑: 直接 加載是 UNRECOVERABLE;產生無效的恢復操作。 表 CSDN,已加載從每個邏輯記錄 插入選項對此表 INSERT 生效 列名 位置 長度 中止 包裝數據類型 ------------------------------ ---------- ----- ---- ---- --------------------- ID FIRST * # CHARACTER PWD NEXT * # CHARACTER EMAIL NEXT * # CHARACTER 表 CSDN: 6428632 行 加載成功。 由於數據錯誤, 0 行 沒有加載。 由於所有 WHEN 子句失敗, 0 行 沒有加載。 由於所有字段都為空的, 0 行 沒有加載。 在直接路徑中沒有使用綁定數組大小。 列數組 行數: 5000 流緩沖區字節數: 256000 讀取 緩沖區字節數: 1048576 跳過的邏輯記錄總數: 0 讀取的邏輯記錄總數: 6428632 拒絕的邏輯記錄總數: 0 廢棄的邏輯記錄總數: 0 由 SQL*Loader 主線程加載的流緩沖區總數: 1497 由 SQL*Loader 加載線程加載的流緩沖區總數: 0 從 星期六 12月 24 16:01:06 2011 開始運行 在 星期六 12月 24 16:01:13 2011 處運行結束 經過時間為: 00: 00: 06.93 CPU 時間為: 00: 00: 04.65從輸出文件可以看出時間為00:00:06.93,將近每秒鍾100W行的導入效率,很不錯。
MySQL
MySQL導入比較簡單,不需要CTRL文件,直接在mysql命令行執行即可。
mysql> LOAD DATA local infile "D:/CSDN/www.csdn.net.sql" into table CSDN fields terminated by '#'; Query OK, 6428632 rows affected, 14275 warnings (1 min 51.95 sec) Records: 6428632 Deleted: 0 Skipped: 0 Warnings: 14275
從打印信息,可以看出,耗時接近2分鍾,性能較差。
DM7
DM7提供了dmfldr.exe工具,需要ctrl文件,用法和oracle基本類似,有些細微的差別,比如指定輸出導入到輸出文件,還是會在CMD中打印信息。
D:\SRC\DM7\Release>dmfldr.exe USERID=SYSDBA/SYSDBA CONTROL='D:/CSDN/dm_csdn.ctrl ' DIRECT=TRUE LOG='OUT.LOG'
輸出文件為OUT.LOG:
dmfldr: Copyright (c) 2011, 2015, Dameng. All rights reserved. 控制文件:D:/CSDN/dm_csdn.ctrl 加載行數:全部 每次提交服務器行數:50000 跳過行數:0 允許錯誤數:100 是否直接加載:是 是否插入自增列:否 數據是否已按照聚集索引排序:否 字符集:GBK 數據文件共1個: D:\CSDN\www.csdn.net.sql 錯誤文件:fldr.bad 目標表:CSDN 列名 終止 包裝數據類型 ID WHT CHARACTER PWD WHT CHARACTER EMAIL WHT CHARACTER 目標表 CSDN : 6428632行 加載成功。 由於數據格式錯誤,0行 丟棄。 由於數據錯誤,0行 沒有加載。 跳過的邏輯記錄總數:0 讀取的邏輯記錄總數:6428632 拒絕的邏輯記錄總數:0 用時:15238.166(ms)
查看輸出文件,用時15s,比MySQL好很多,比Oralce差一點。
聚集函數性能測試
這里的測試我們使用網上用來統計密碼使用次數TOP 10的語句,大家都知道Oracle沒有TOP N,取而代之的是ROWNUM,MySQL也沒有TOP N,取而代之的是LIMIT,DM7支持TOP N、ROWNUM和LIMIT三種語法。所有的測試都關閉了結果集重用。
ORACLE
Oracle沒有進行相關的設置,使用了默認配置。
SQL> SELECT CNT, PWD FROM (SELECT COUNT(PWD) as cnt, PWD FROM CSDN GROUP BY PWD ORDER BY COUNT(PWD) DESC ) WHERE ROWNUM < 11; CNT PWD ---------- -------------------- 235017 123456789 212759 12345678 76348 11111111 46053 dearbook 34953 00000000 20010 123123123 17793 1234567890 15033 88888888 6995 111111111 5965 147258369 已選擇10行。 已用時間: 00: 00: 11.09
ORACLE用時11S,我們來看下Oracle的執行計划:
執行計划 ---------------------------------------------------------- Plan hash value: 3269342783 -------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 10 | 1430 | 11354 (5)| 00:02:17 | |* 1 | COUNT STOPKEY | | | | | | | 2 | VIEW | | 6856K| 935M| 11354 (5)| 00:02:17 | |* 3 | SORT ORDER BY STOPKEY| | 6856K| 850M| 11354 (5)| 00:02:17 | | 4 | HASH GROUP BY | | 6856K| 850M| 11354 (5)| 00:02:17 | | 5 | TABLE ACCESS FULL | CSDN | 6856K| 850M| 10890 (1)| 00:02:11 | -------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(ROWNUM<11) 3 - filter(ROWNUM<11) Note ----- - dynamic sampling used for this statement 統計信息 ---------------------------------------------------------- 133 recursive calls 0 db block gets 39767 consistent gets 56161 physical reads 0 redo size 684 bytes sent via SQL*Net to client 416 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 1 sorts (memory) 0 sorts (disk) 10 rows processed
執行計划可以看出來,由於沒有索引,首先進行了全表掃描,然后根據PWD進行HASH,按照COUNT進行SORT,構建一個臨時的VIEW,然后是過濾rownum<11。
下面對PWD列創建索引,看下Oracle是否能利用這個索引。
SQL> CREATE INDEX I1 ON CSDN(PWD); 索引已創建。 已用時間: 00: 00: 27.17
查看下執行計划:
SQL> SELECT CNT, PWD FROM (SELECT COUNT(PWD) as cnt, PWD FROM CSDN GROUP BY PWD ORDER BY COUNT(PWD) DESC ) WHERE ROWNUM < 11; 已選擇10行。 已用時間: 00: 00: 10.31 執行計划 ---------------------------------------------------------- Plan hash value: 3269342783 -------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 10 | 1430 | 11354 (5)| 00:02:17 | |* 1 | COUNT STOPKEY | | | | | | | 2 | VIEW | | 6856K| 935M| 11354 (5)| 00:02:17 | |* 3 | SORT ORDER BY STOPKEY| | 6856K| 850M| 11354 (5)| 00:02:17 | | 4 | HASH GROUP BY | | 6856K| 850M| 11354 (5)| 00:02:17 | | 5 | TABLE ACCESS FULL | CSDN | 6856K| 850M| 10890 (1)| 00:02:11 | -------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(ROWNUM<11) 3 - filter(ROWNUM<11) Note ----- - dynamic sampling used for this statement 統計信息 ---------------------------------------------------------- 133 recursive calls 0 db block gets 39776 consistent gets 32748 physical reads 0 redo size 684 bytes sent via SQL*Net to client 416 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 1 sorts (memory) 0 sorts (disk) 10 rows processed可以看到時間並沒有提升,ORACLE並沒有利用到索引。
MySQL
MySQL設置了INNODB的BUFFER大小為700M,執行如下語句:
SELECT PWD, COUNT(PWD) FROM CSDN GROUP BY PWD ORDER BY COUNT(PWD) DESC LIMIT 10;
長時間木有相應啊,打了倆小時羽毛球回來,還是沒執行完....
設置了SROT BUFFER后仍無效果,嘗試創建索引,發現很慢,慢到簡直就是挑戰我的極限,so close it。INNODB的測試結果有些失望,可能是我設置的參數不夠,希望有經驗的同學嘗試下,指點下~~。
DM7
DM7設置了BUFFER大小也為700M。
SELECT TOP 10 PWD, COUNT(PWD) FROM CSDN GROUP BY PWD ORDER BY COUNT(PWD) DESC; PWD COUNT(PWD) 1 123456789 235029 2 12345678 212761 3 11111111 76348 4 dearbook 46053 5 00000000 34953 6 123123123 20010 7 1234567890 17794 8 88888888 15033 9 111111111 6995 10 147258369 5966 10 rows got time used: 12186.676(ms) clock tick:1383768307. Execute id is 1.
執行時間為12S,第二次和第三次執行時,時間會縮短為7S左右,因為數據全部緩存在buffer中,沒有I/O。有同學可能發現和oracle比較有些count計算不一致,這是因為存在一些密碼結尾為空格的數據,DM的處理在這里類似SQL SERVER了...
查看下執行計划:
SQL>EXPLAIN SELECT TOP 10 PWD, COUNT(PWD) FROM CSDN GROUP BY PWD ORDER BY COUNT( PWD) DESC; EXPLAIN SELECT TOP 10 PWD, COUNT(PWD) FROM CSDN GROUP BY PWD ORDER BY COUNT(PWD) DESC; #NSET2: [0, 0, 0] #PRJT2: [0, 0, 0]; exp_num(2), is_atom(FALSE) #SORT3: [0, 0, 0]; key_num(1), is_distinct(FALSE) #HAGR2: [0, 0, 0]; grp_num(1), sfun_num(2) #CSCN2: [2721, 6428632, 0]; INDEX33555437(CSDN) time used: 0.732(ms) clock tick:2138943. Execute id is 0.
可以看出,DM7也首先進行了全表掃描SCAN,然后針對GROUP BY執行了HASH AGR,針對ORDER BY執行了SORT節點。
DM7同時支持查看每個執行節點的執行時間:
SQL>select n.name, time_used, n_enter from v$sql_node_name n, v$sql_node_history h where n.type$ = h.type$ and exec_id = 1 order by seq_no; select n.name, time_used, n_enter from v$sql_node_name n, v$sql_node_history h w here n.type$ = h.type$ and exec_id = 1 order by seq_no; NAME TIME_USED N_ENTER 1 DLCK 2 2 2 NSET2 71 3 3 PRJT2 2 4 4 SORT3 470170 4038 5 HAGR2 6467980 10466 6 CSCN2 5222702 6430 6 rows got time used: 15.969(ms) clock tick:46813291. Execute id is 4.
這個比較方便了,可以知道性能瓶頸是在哪個執行節點,如果實在CSCN,那就是I/O的問題了,如果是HAGR或者是SORT,那可能就需要調整下相應的BUFFER了。
下面創建索引試下:
CREATE INDEX I1 ON CSDN(PWD); time used: 25562.295(ms) clock tick:1959731992. Execute id is 1.
首先看下執行計划是否改變,如果沒變的話,我們就不需要再去執行看時間了:
SQL>EXPLAIN SELECT TOP 10 PWD, COUNT(PWD) FROM CSDN GROUP BY PWD ORDER BY COUNT( PWD) DESC; EXPLAIN SELECT TOP 10 PWD, COUNT(PWD) FROM CSDN GROUP BY PWD ORDER BY COUNT(PWD) DESC; #NSET2: [0, 0, 0] #PRJT2: [0, 0, 0]; exp_num(2), is_atom(FALSE) #SORT3: [0, 0, 0]; key_num(1), is_distinct(FALSE) #SAGR2: [0, 0, 0]; grp_num(1), sfun_num(2) #SSCN: [928, 6428632, 0]; I1(CSDN) time used: 0.459(ms) clock tick:1340375. Execute id is 0.
執行計划發生了變化,可以看到SSCN里面是使用了I1索引,同時HAGR也改為了SAGR,看下這個新的執行計划是否是最好的。
SQL>SELECT TOP 10 PWD, COUNT(PWD) FROM CSDN GROUP BY PWD ORDER BY COUNT(PWD) DES C; SELECT TOP 10 PWD, COUNT(PWD) FROM CSDN GROUP BY PWD ORDER BY COUNT(PWD) DESC; PWD COUNT(PWD) 1 123456789 235029 2 12345678 212761 3 11111111 76348 4 dearbook 46053 5 00000000 34953 6 123123123 20010 7 1234567890 17794 8 88888888 15033 9 111111111 6995 10 147258369 5966 10 rows got time used: 1897.215(ms) clock tick:1269554324. Execute id is 4.
時間縮短為1897.215(ms),可以看到DM7在執行計划的選擇上更加精確一點。
小結
通過上面簡單的測試,可以看出在文本數據導入方面Oracle比較快,DM7緊隨其后,MySQL就略顯不足了。在聚集函數和排序處理方面,DM7的計划選擇更加精確一點,Oracle表現中規中矩,MySQL的復雜查詢一直是軟肋,可能和插件式的存儲引擎設計模式有關系,支持多種存儲引擎導致其優化器的設計是比較通用,通用的結果就無法進行精確的優化。
經過@CFR同學的提醒,進行了這個比較粗略的測試,從庫的下載到導入到測試,還是花費了一點時間,發這個博文很糾結,怕同學說我是水文,最后聲明下吧,以上數據均是實際測試結果。最后再次感謝下CSDN^_^