yanagishimaでなぜJDBCを使ってないのか
約2年前にyanagishimaを開発し始めた時、Javaで実装することに迷いは無かった。
理由は単純に僕が一番馴染んでいる言語だから。
Javaで実装している一方でJDBCを使わなかったのには2つの理由がある。
一つ目は性能面を考慮したから。やりたいこととしてはデータとカラム名の両方を取りたい。なぜならそうしないとどのデータがどのカラムに対応するかわかりづらいから。
JDBCを使う場合はデータを取るためには
https://prestodb.io/resources.html#libraries
にあるようにStatement#executeQueryをよんでそのあとはResultSetをごにょればいいです。
下記のように
String sql = "SELECT * FROM sys.node"; String url = "jdbc:presto://localhost:8080/catalog/schema"; try (Connection connection = DriverManager.getConnection(url, "test", null)) { try (Statement statement = connection.createStatement()) { try (ResultSet rs = statement.executeQuery(sql)) { while (rs.next()) { System.out.println(rs.getString("node_id")); } } } }
カラム名を取るにはどうするかというと、DatabaseMetaData#getColumns
を呼びます。
これを呼ぶとどうなるかというともう一回prestoにクエリを投げることになります。
どんなクエリかというとこんな感じです。
SELECT TABLE_CAT, TABLE_SCHEM, TABLE_NAME, COLUMN_NAME, DATA_TYPE, TYPE_NAME, COLUMN_SIZE, BUFFER_LENGTH, DECIMAL_DIGITS, NUM_PREC_RADIX, NULLABLE, REMARKS, COLUMN_DEF, SQL_DATA_TYPE, SQL_DATETIME_SUB, CHAR_OCTET_LENGTH, ORDINAL_POSITION, IS_NULLABLE, SCOPE_CATALOG, SCOPE_SCHEMA, SCOPE_TABLE, SOURCE_DATA_TYPE, IS_AUTOINCREMENT, IS_GENERATEDCOLUMN FROM system.jdbc.columns WHERE TABLE_CAT = 'hive' AND TABLE_NAME LIKE '%' AND COLUMN_NAME LIKE '%' ORDER BY TABLE_CAT, TABLE_SCHEM, TABLE_NAME, ORDINAL_POSITION
presto-jdbcのソース的にはこの辺
https://github.com/prestodb/presto/blob/b316dbbe9edb281a2bede6ab08c0249586197f1e/presto-jdbc/src/main/java/com/facebook/presto/jdbc/PrestoDatabaseMetaData.java#L963
ようはデータとカラム名の両方を取るためにはprestoに2回クエリを投げる必要があります。
しかもカラム名を取るクエリは意外と遅いです。僕の環境だと10秒ぐらいかかります。
それがあってyanagshimaではJDBCを使っていません。presto-cliのコードを参考に直接JSON APIをたたいています。
2つ目の理由はJDBCを使うとクエリのキャンセルができないからです。
これはpresto-jdbcがStatement#cancelを実装していないからです。
https://github.com/prestodb/presto/blob/07f430b6f27371d5b53ab2795016b810f0f67ab3/presto-jdbc/src/main/java/com/facebook/presto/jdbc/PrestoStatement.java#L170
yanagishimaではクエリのキャンセルのためにHTTP DELETEを投げてます。
これはpresto web uiでキャンセルするときと同じです。
この辺のHTTP API仕様を下記にも書かれています。
https://github.com/prestodb/presto/wiki/HTTP-Protocol
なおZeppelinだとpresto JDBCを使うのでデータとカラム名を取るために2回のリクエストを投げ、そしてクエリのキャンセルはできません。