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

SQLLIMITとJDBCステートメントのsetMaxRows。どちらの方がよいですか?

    SQLレベルの制限

    SQLクエリ結果セットのサイズを制限するには、SQL:008構文を使用できます。

    SELECT title
    FROM post
    ORDER BY created_on DESC
    OFFSET 50 ROWS
    FETCH NEXT 50 ROWS ONLY
    

    これは、Oracle 12、SQL Server 2012、またはPostgreSQL8.4以降のバージョンで動作します。

    MySQLの場合、LIMIT句とOFFSET句を使用できます。

    SELECT title
    FROM post
    ORDER BY created_on DESC
    LIMIT 50
    OFFSET 50
    

    SQLレベルのページ付けを使用する利点は、データベース実行プランでこの情報を使用できることです。

    したがって、created_onにインデックスがある場合 列:

    CREATE INDEX idx_post_created_on ON post (created_on DESC)
    

    そして、LIMITを使用して次のクエリを実行します 条項:

    EXPLAIN ANALYZE
    SELECT title
    FROM post
    ORDER BY created_on DESC
    LIMIT 50
    

    オプティマイザーは50レコードのみがフェッチされることを認識しているため、データベースエンジンがインデックスを使用していることがわかります。

    Execution plan:
    Limit  (cost=0.28..25.35 rows=50 width=564)
           (actual time=0.038..0.051 rows=50 loops=1)
      ->  Index Scan using idx_post_created_on on post p  
          (cost=0.28..260.04 rows=518 width=564) 
          (actual time=0.037..0.049 rows=50 loops=1)
    Planning time: 1.511 ms
    Execution time: 0.148 ms
    

    JDBCステートメントmaxRows

    setMaxRows Javadoc

    それはあまり安心できません!

    したがって、PostgreSQLで次のクエリを実行すると:

    try (PreparedStatement statement = connection
        .prepareStatement("""
            SELECT title
            FROM post
            ORDER BY created_on DESC
        """)
    ) {
        statement.setMaxRows(50);
        ResultSet resultSet = statement.executeQuery();
        int count = 0;
        while (resultSet.next()) {
            String title = resultSet.getString(1);
            count++;
        }
    }
    

    PostgreSQLログに次の実行プランが記録されます。

    Execution plan:
      Sort  (cost=65.53..66.83 rows=518 width=564) 
            (actual time=4.339..5.473 rows=5000 loops=1)
      Sort Key: created_on DESC
      Sort Method: quicksort  Memory: 896kB
      ->  Seq Scan on post p  (cost=0.00..42.18 rows=518 width=564) 
                              (actual time=0.041..1.833 rows=5000 loops=1)
    Planning time: 1.840 ms
    Execution time: 6.611 ms 
    

    データベースオプティマイザは、50レコードのみをフェッチする必要があることを認識していないため、5000行すべてをスキャンする必要があると想定しています。クエリで多数のレコードをフェッチする必要がある場合、全表スキャンのコストは実際にはインデックスを使用する場合よりも低くなるため、実行プランではインデックスをまったく使用しません。

    結論

    setMaxRowsのように見えますが ResultSetのサイズを制限するためのポータブルソリューションです。 、データベースサーバーオプティマイザがJDBC maxRowsを使用しない場合、SQLレベルのページ付けははるかに効率的です。 プロパティ。



    1. SQLとPrestoを使用したビッグデータ分析クエリの実行

    2. MySQLで多対多の関係で選択する

    3. 予期しないT_ENCAPSED_AND_WHITESPACE、T_STRINGまたはT_VARIABLEまたはT_NUM_STRINGエラーが予想されます

    4. SQL - オペランドのデータ型 datetime2 は減算演算子には無効です