sql >> データベース >  >> RDS >> Oracle

Spring の遅いメタデータ フェッチ Oracle を使用した JDBC

    クライアントとサーバー間の実際の通信をリバース エンジニアリングすると、Oracle の DatabaseMetaData.getColumns() メソッドが次の SQL クエリを送信することがわかります (ただし、これは ODBC ドライバーのバージョンと設定によって異なる場合があります)。

        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;
    

    特に ALL_TAB_COLS および ALL_TYPES テーブルはそれぞれ数千のレコード長になる可能性があるため、少し遅い理由がわかります。それにもかかわらず、Oracle が最初の呼び出し (数分) を実行するのに苦労している間、後続の呼び出しはほぼ瞬時に結果を返します。これは、データのサブセットが必要であるにもかかわらず、エンジンが前にデータセット全体を結合する、古典的なテーブル結合のパフォーマンスの問題です。 必要なサブセットを計算して配信します。その後のデータ/結果のキャッシュは、後続のクエリのパフォーマンスを向上させるために機能します。

    より良い解決策は、get_ddl() を使用し、返されたテーブル定義を このスレッド .

    または 次のように、ダミー クエリを実行してから resultSetMetadata を使用すると、テーブルのメタデータをより高速にクエリできる場合があります (注:列のコメントのメタデータはすぐには利用できない場合があります)。

        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....
        }
    


    1. MySQLがJOINplusORDERで主キーを使用しないのはなぜですか?

    2. このクエリで定義されたヒントのため、クエリプロセッサはクエリプランを作成できませんでした。 SET FORCEPLANを使用せずに、クエリを再送信します

    3. SQLServerコンマを含むデータを含むcsvを一括挿入

    4. MySql、日付と時刻の列をタイムスタンプに結合