Oracle主鍵選擇對插入的影響

壹頁書發表於2014-01-01
主鍵一般使用序列或者UUID
使用UUID主要優點是分散式環境下,主鍵不會重複;缺點是效能相對較低。
序列則相反,他在分散式環境下會重複,但是效能較高。

實驗分別測試序列,UUID,使用RAW型別的UUID,測試100W資料插入的時間。
建立實驗所需的表
  1. drop table test_seq purge;
  2. drop table test_uuid purge;
  3. drop table test_uuid_raw purge;

  4. --測試序列
  5. create table test_seq(t_id number(8) primary key );
  6. --測試UUID
  7. create table test_uuid(t_id varchar2(32) primary key);
  8. --測試UUID RAW
  9. create table test_uuid_raw(t_id raw(16) primary key);
  10.  
  11. drop sequence seq;

  12. create sequence seq
  13. increment by 1
  14. start with 1
  15. cache 300;
  1. import java.sql.Connection;
  2. import java.sql.DriverManager;
  3. import java.sql.PreparedStatement;
  4. import java.sql.SQLException;
  5. import java.util.UUID;

  6. import org.apache.commons.codec.DecoderException;
  7. import org.apache.commons.codec.binary.Hex;

  8. public class PrimaryKeyTest {
  9.     private static int _1W = 10000;
  10.     private static int COUNT = _1W * 100;
  11.     private static String URL = "jdbc:oracle:thin:127.0.0.1:1521:orcl";
  12.     private static String USERNAME = "edmond";
  13.     private static String PWD = "edmond";

  14.     private static void insertSeq() throws SQLException {
  15.         System.out.println("測試序列:");
  16.         long start = System.currentTimeMillis();
  17.         long end;
  18.         Connection con = DriverManager.getConnection(URL, USERNAME, PWD);
  19.         con.setAutoCommit(false);
  20.         PreparedStatement ps = con.prepareStatement("insert into test_seq(t_id) values(seq.nextval)");
  21.         for (int i = 0; i < COUNT; i++) {
  22.             if (i == _1W) {
  23.                 end = System.currentTimeMillis();
  24.                 System.out.println("1W:" + (end - start));
  25.             } else if (i == _1W * 10) {
  26.                 end = System.currentTimeMillis();
  27.                 System.out.println("10W:" + (end - start));
  28.             } else if (i == _1W * 20) {
  29.                 end = System.currentTimeMillis();
  30.                 System.out.println("20W:" + (end - start));
  31.             } else if (i == _1W * 50) {
  32.                 end = System.currentTimeMillis();
  33.                 System.out.println("50W:" + (end - start));
  34.             } else if (i == _1W * 80) {
  35.                 end = System.currentTimeMillis();
  36.                 System.out.println("80W:" + (end - start));
  37.             }

  38.             ps.addBatch();
  39.             if (i % (10 * _1W) == 0) {
  40.                 ps.executeBatch();
  41.             }
  42.         }
  43.         ps.executeBatch();
  44.         con.commit();
  45.         ps.close();
  46.         con.close();

  47.         end = System.currentTimeMillis();
  48.         System.out.println("100W:" + (end - start));

  49.     }

  50.     private static void insertUUID() throws SQLException {
  51.         System.out.println("測試UUID:");
  52.         long start = System.currentTimeMillis();
  53.         long end;
  54.         Connection con = DriverManager.getConnection(URL, USERNAME, PWD);
  55.         con.setAutoCommit(false);
  56.         PreparedStatement ps = con.prepareStatement("insert into test_uuid(t_id) values(?)");
  57.         for (int i = 0; i < COUNT; i++) {
  58.             if (i == _1W) {
  59.                 end = System.currentTimeMillis();
  60.                 System.out.println("1W:" + (end - start));
  61.             } else if (i == _1W * 10) {
  62.                 end = System.currentTimeMillis();
  63.                 System.out.println("10W:" + (end - start));
  64.             } else if (i == _1W * 20) {
  65.                 end = System.currentTimeMillis();
  66.                 System.out.println("20W:" + (end - start));
  67.             } else if (i == _1W * 50) {
  68.                 end = System.currentTimeMillis();
  69.                 System.out.println("50W:" + (end - start));
  70.             } else if (i == _1W * 80) {
  71.                 end = System.currentTimeMillis();
  72.                 System.out.println("80W:" + (end - start));
  73.             }

  74.             String id = UUID.randomUUID().toString().replaceAll("-", "");
  75.             ps.setString(1, id);
  76.             ps.addBatch();

  77.             if (i % (10 * _1W) == 0) {
  78.                 ps.executeBatch();
  79.             }
  80.         }
  81.         ps.executeBatch();
  82.         con.commit();
  83.         ps.close();
  84.         con.close();

  85.         end = System.currentTimeMillis();
  86.         System.out.println("100W:" + (end - start));

  87.     }

  88.     private static void insertUUIDRaw() throws SQLException, DecoderException {
  89.         System.out.println("測試UUID RAW:");
  90.         long start = System.currentTimeMillis();
  91.         long end;
  92.         Connection con = DriverManager.getConnection(URL, USERNAME, PWD);
  93.         con.setAutoCommit(false);
  94.         PreparedStatement ps = con.prepareStatement("insert into test_uuid_raw(t_id) values(?)");
  95.         for (int i = 0; i < COUNT; i++) {
  96.             if (i == _1W) {
  97.                 end = System.currentTimeMillis();
  98.                 System.out.println("1W:" + (end - start));
  99.             } else if (i == _1W * 10) {
  100.                 end = System.currentTimeMillis();
  101.                 System.out.println("10W:" + (end - start));
  102.             } else if (i == _1W * 20) {
  103.                 end = System.currentTimeMillis();
  104.                 System.out.println("20W:" + (end - start));
  105.             } else if (i == _1W * 50) {
  106.                 end = System.currentTimeMillis();
  107.                 System.out.println("50W:" + (end - start));
  108.             } else if (i == _1W * 80) {
  109.                 end = System.currentTimeMillis();
  110.                 System.out.println("80W:" + (end - start));
  111.             }

  112.             byte[] data = Hex.decodeHex(UUID.randomUUID().toString().replaceAll("-", "").toCharArray());
  113.             ps.setBytes(1, data);
  114.             ps.addBatch();

  115.             if (i % (10 * _1W) == 0) {
  116.                 ps.executeBatch();
  117.             }
  118.         }
  119.         ps.executeBatch();
  120.         con.commit();
  121.         ps.close();
  122.         con.close();

  123.         end = System.currentTimeMillis();
  124.         System.out.println("100W:" + (end - start));
  125.     }

  126.     public static void main(String[] args) throws ClassNotFoundException, SQLException, DecoderException {
  127.         Class.forName("oracle.jdbc.OracleDriver");
  128.         insertSeq();
  129.         insertUUID();
  130.         insertUUIDRaw();
  131.     }
  132. }
測試結果如下:
1w 10w 20w 50w 80w 100w
序列 939 949 1584 3847 7732 12010
UUID Varchar2 2196 2915 14591 107528 861084 3051716
UUID RAW 607 1237 9302 37817 169935 986043

不同的主鍵方案,不僅對索引維護有效能影響,同時也對索引的使用造成影響。(UUID作為主鍵索引的value佔用空間比序列大很多)。





同樣的查詢需求,都使用了主鍵索引,但是採用UUID作為主鍵,他的物理讀和一致性讀都遠遠超過了採用序列的情況。
所以如果沒有分散式環境的需求(例如層級資料上報),可以儘量採用序列作為主鍵。
單純就插入效能而言,序列>UUID RAW>UUID Varchar2

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29254281/viewspace-1066263/,如需轉載,請註明出處,否則將追究法律責任。

相關文章