2012-01-09 31 views
5

Tôi đang sử dụng phương pháp Spring JdbcUtils.extractDatabaseMetaData() để phân tích cơ sở dữ liệu. Hàm gọi một cuộc gọi lại và bàn giao đối tượng DatabaseMetaData. Đối tượng này cung cấp getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern).JDBC với siêu dữ liệu chậm Spring tìm nạp Oracle

Tôi gọi nó là số này getColumns("",TABLE_OWNER_USERNAME,null,null) và nhận được 400 cột. Đây là những kết quả chính xác mà tôi muốn, nhưng yêu cầu mất hơn 1 phút.

Tôi có thể tối ưu hóa truy vấn này nhanh không? Kéo 400 hàng sẽ xảy ra trong 1 giây và không phải một phút.

EDIT: Tôi không nghi ngờ phần Spring đang chậm. Phân tích chặt chẽ hơn cho thấy việc tìm nạp DatabaseMetaData mất vài giây nhưng việc thực hiện getColumns() mất nhiều thời gian.

+0

Bạn chắc chắn đó là lỗi của Springs? Bạn có thể chạy cùng một truy vấn bằng cách sử dụng JDBC đơn giản hoặc có thể trực tiếp trong bảng điều khiển cơ sở dữ liệu không? –

+0

Tôi không nghĩ đó là lỗi của lò xo. Vấn đề là, nó không phải là một truy vấn cho mỗi se. Trình điều khiển JDBC giấu truy vấn thực sự thông qua phương thức 'getColumns()', vì vậy tôi không thể thấy điều gì đang thực sự xảy ra. –

+1

@FranzKafka - Bạn có thể theo dõi SQL mà Spring tạo để xác định chính xác (các) bảng từ điển dữ liệu nào đang được truy vấn không? Thống kê có được thu thập trên từ điển dữ liệu không? –

Trả lời

2

Có thể đó là cách tiếp cận tốt hơn để truy vấn ALL_TAB_COLUMNS. Dưới đây là một ví dụ:

public final List<Column> getColumnsByOwner(final String owner) { 
    final String sql = "SELECT COLUMN_NAME, DATA_TYPE, DATA_LENGTH, " 
      + " DATA_PRECISION, DATA_SCALE, NULLABLE, DATA_DEFAULT" 
      + " FROM ALL_TAB_COLUMNS" 
      + " WHERE OWNER = ? ORDER BY COLUMN_ID"; 

    return jdbcTemplate.query(sql, 
      new Object[] { owner }, 
      new RowMapper<Column>() { 
       @Override 
       public Column mapRow(final ResultSet res, final int rowNum) 
         throws SQLException { 
        final Column reg = new Column(); 

        reg.setColumnName(res.getString("COLUMN_NAME")); 
        //Read other properties 
        reg.setNullable(res.getString("NULLABLE").equals("Y")); 
        return reg; 
       } 
      }); 
} 

Nếu bạn cần lọc theo bảng chỉ cần thêm "VÀ TABLE_NAME =?" để sql và tableName như một tham số khác.

Hy vọng điều đó sẽ hữu ích.

2

Có ngược lại thiết kế thực sự truyền thông giữa máy khách và máy chủ tôi có thể tiết lộ rằng DatabaseMetaData.getColumns của Oracle() phương pháp gửi các truy vấn SQL sau đây (mặc dù điều này có thể thay đổi với phiên bản ODBC driver và cài đặt):

declare 
    in_owner varchar2(128); 
    in_name varchar2(128); 
    in_column varchar2(128); 
    xyzzy SYS_REFCURSOR; 
    begin 
    in_owner := :1; // Which resolves to the schema (user) name supplied 
    in_name := :2; // Which resolves to the table name supplied 
    in_column := :3; // Which gets set to '%'; 
    open xyzzy for 
    SELECT NULL AS table_cat, 
     t.owner AS table_schem, 
     t.table_name AS table_name, 
     t.column_name AS column_name, 
    DECODE( (SELECT a.typecode 
     FROM ALL_TYPES A 
     WHERE a.type_name = t.data_type), 
    'OBJECT', 2002, 
    'COLLECTION', 2003, 
    DECODE(substr(t.data_type, 1, 9), 
     'TIMESTAMP', 
     DECODE(substr(t.data_type, 10, 1), 
      '(', 
      DECODE(substr(t.data_type, 19, 5), 
       'LOCAL', -102, 'TIME ', -101, 93), 
      DECODE(substr(t.data_type, 16, 5), 
      'LOCAL', -102, 'TIME ', -101, 93)), 
     'INTERVAL ', 
     DECODE(substr(t.data_type, 10, 3), 
     'DAY', -104, 'YEA', -103), 
     DECODE(t.data_type, 
     'BINARY_DOUBLE', 101, 
     'BINARY_FLOAT', 100, 
     'BFILE', -13, 
     'BLOB', 2004, 
     'CHAR', 1, 
     'CLOB', 2005, 
     'COLLECTION', 2003, 
     'DATE', 93, 
     'FLOAT', 6, 
     'LONG', -1, 
     'LONG RAW', -4, 
     'NCHAR', -15, 
     'NCLOB', 2011, 
     'NUMBER', 2, 
     'NVARCHAR', -9, 
     'NVARCHAR2', -9, 
     'OBJECT', 2002, 
     'OPAQUE/XMLTYPE', 2009, 
     'RAW', -3, 
     'REF', 2006, 
     'ROWID', -8, 
     'SQLXML', 2009, 
     'UROWI', -8, 
     'VARCHAR2', 12, 
     'VARRAY', 2003, 
     'XMLTYPE', 2009, 
     1111))) 
    AS data_type, 
     t.data_type AS type_name, 
     DECODE (t.data_precision, null, 
      DECODE(t.data_type, 'NUMBER', 
       DECODE(t.data_scale, null, 0 , 38), 
        DECODE (t.data_type, 'CHAR', t.char_length, 'VARCHAR', t.char_length, 'VARCHAR2', t.char_length, 'NVARCHAR2', t.char_length, 'NCHAR', t.char_length, 'NUMBER', 0, t.data_length)), t.data_precision) 
     AS column_size, 
     0 AS buffer_length, 
     DECODE (t.data_type, 'NUMBER', DECODE(t.data_precision, null, DECODE(t.data_scale, null, -127 , t.data_scale), t.data_scale), t.data_scale) AS decimal_digits, 
     10 AS num_prec_radix, 
     DECODE (t.nullable, 'N', 0, 1) AS nullable, 
     NULL AS remarks, 
     t.data_default AS column_def, 
     0 AS sql_data_type, 
     0 AS sql_datetime_sub, 
     t.data_length AS char_octet_length, 
     t.column_id AS ordinal_position, 
     DECODE (t.nullable, 'N', 'NO', 'YES') AS is_nullable, 
     null as SCOPE_CATALOG, 
     null as SCOPE_SCHEMA, 
     null as SCOPE_TABLE, 
     null as SOURCE_DATA_TYPE, 
     'NO' as IS_AUTOINCREMENT, 
     t.virtual_column as IS_GENERATEDCOLUMN 
    FROM all_tab_cols t 
    WHERE t.owner LIKE in_owner ESCAPE '/' 
    AND t.table_name LIKE in_name ESCAPE '/' 
    AND t.column_name LIKE in_column ESCAPE '/' 
    AND t.user_generated = 'YES' 
    ORDER BY table_schem, table_name, ordinal_position; 
    end; 

Bạn có thể đánh giá cao lý do tại sao có thể hơi chậm, đặc biệt là các bảng ALL_TAB_COLS và ALL_TYPES mỗi bảng có thể dài 1000 bản ghi. Tuy nhiên, trong khi Oracle đấu tranh để thực hiện lời gọi đầu tiên (phút), các cuộc gọi tiếp theo trả về kết quả gần như ngay lập tức. Đây là một vấn đề hiệu suất bảng-tham gia cổ điển mà mặc dù một tập hợp con dữ liệu được yêu cầu động cơ tham gia toàn bộ tập dữ liệu trước khi tính toán và phân phối tập hợp con được yêu cầu. Sau đó dữ liệu/kết quả bộ nhớ đệm hoạt động để cải thiện hiệu suất của các truy vấn tiếp theo.

Giải pháp tốt hơn có thể là sử dụng get_ddl() và phân tích cú pháp định nghĩa bảng trả lại theo this thread.

Ngoài ra bạn có thể truy vấn các siêu dữ liệu vào một bảng nhanh hơn bằng cách thực hiện một truy vấn giả sau đó sử dụng ResultSetMetaData như sau (Lưu ý: nhận xét cột siêu dữ liệu có thể không có ngay lập tức):

ResultSet rs = connection.CreateStatement.executeQuery("SELECT * from MyTable WHERE 1=0"); 
    ResultSetMetaData md = rs.getMetaData(); 
    for (int ix = 1; ix <= md.getColumnCount(); ix++) 
    { 
     int colSize = md.getPrecision(ix); 
     String nativeType = md.getColumnTypeName(ix); 
     int jdbcType = md.getColumnType(ix); 
     // and so on.... 
    } 
Các vấn đề liên quan