54 SDB環境でのルーティング

Oracle Shardingでは、2種類のルーティングをサポートしています。

次の項では、SDB環境でのルーティングについて説明します。

54.1 シャードへの直接ルーティング

Oracleクライアントおよび接続プールは、高パフォーマンスのデータ依存ルーティングのために接続文字列に指定されたシャーディング・キーを認識できます。接続レイヤーのシャード・ルーティング・キャッシュは、データが常駐するシャードにデータベース・リクエストを直接ルーティングするために使用されます。

次の項では、シャードへの直接ルーティングについて説明します。

54.1.1 シャードへの直接ルーティングについて

シャードへの直接ルーティングでは、必要なトランザクションに関連するデータが含まれている単一の関連するシャードに対して、シャーディング・キーを使用して接続が確立されます。

接続のチェック時にユーザー・セッション・レベルでデータベース接続リクエストをルーティングするために、シャーディング・キーが使用されます。コンポジット・シャーディング方法では、シャーディング・キーおよびスーパー・シャーディング・キーの両方が必要となります。直接ルーティングでは、シャーディング・キー(またはスーパー・シャーディング・キー)を接続の一部として渡す必要があります。この情報に基づいて、指定されたシャーディング・キーまたはスーパー・シャーディング・キーに関係するデータが含まれている関連するシャードに対して、接続が確立されます。

シャードとのセッションが確立されると、すべてのSQL問合せおよびDMLが該当するシャードのスコープ内でサポートされ、実行されます。このルーティングは高速であり、シャード内トランザクションを実行するすべてのOLTPワークロードで使用されます。最高のパフォーマンスおよび可用性を必要とするすべてのOLTPワークロードに直接ルーティングを使用することをお薦めします。

Oracle Shardingをサポートするために、Oracle接続プールおよびドライバに対して重要な機能強化が行われました。Oracle Database 12cリリース2以降では、JDBC、UCP (Universal Connection Pool)、OCI (OCI Session Pool)およびODP.NET (Oracle Data Provider for .NET)は、接続作成中にシャーディング・キーを渡すための新しいAPIを提供しています。Apache Tomcat、IBM Websphere、Oracle WebLogic ServerおよびJBOSSでは、JDBC/UCPのサポートを活用してシャーディングを使用できます。PHP、Python、PerlおよびNode.jsではOCIのサポートを活用できます。

シャード・トポロジ・キャッシュは、シャードとシャーディング・キーの範囲のマッピングです。Oracle統合接続プールは、このシャード・トポロジ・キャッシュをそのメモリー内に保持します。特定のシャードへの最初の接続時(プールの初期化時またはプールが新しいシャードに接続するとき)に、シャーディング・キーの範囲のマッピングがシャードから収集されて、シャード・トポロジ・キャッシュが動的に作成されます。

シャード・トポロジをキャッシュすると、シャードへの高速なパスが作成され、シャードへの接続を作成するプロセスが迅速になります。シャーディング・キーを使用して接続リクエストが実行されると、接続プールはこの特定のシャーディング・キーが存在する対応するシャードを検索します(トポロジ・キャッシュから)。一致する接続がプールで利用できる場合、プールは内部接続選択アルゴリズムを適用することによって、シャードへの接続を返します。

キャッシュされたトポロジ・マップに存在する特定のシャーディング・キーへのデータベース接続リクエストは、そのシャードに直接送られます(つまり、シャード・ディレクタがバイパスされます)。また、接続プールは、SDBからRLB通知をサブスクライブし、実行時ロード・バランシング・アドバイザに基づいて最適な接続を分配します。接続が確立されると、クライアントはシャードに対するトランザクションを直接実行します。指定したシャーディング・キーのすべてのトランザクションが実行されたら、アプリケーションはその接続をプールに返し、別のキーの接続を取得する必要があります。

一致する接続がプールにない場合は、シャーディング・キーとともに接続リクエストをシャード・ディレクタに転送することによって、新しい接続が作成されます。

プールが初期化され、シャード・トポロジ・キャッシュがすべてのシャードに基づいて作成されると、シャード・ディレクタが停止しても直接ルーティングに影響しなくなります。

54.1.2 シャーディングAPI

Oracle接続プールおよびドライバはOracle Shardingをサポートしています。

JDBC、UCP、OCIおよびOracle Data Provider for .NET (ODP.NET)は、接続チェックの一部としてシャーディング・キーを認識します。Apache Tomcat、WebsphereおよびWebLogicはシャーディングのためのUCPサポートを活用し、PHP、Python、PerlおよびNode.jsはOCIサポートを活用します。

Oracle UCPのシャーディングAPI

シャード対応のアプリケーションは、createShardingKeyBuilderおよびcreateConnectionBuilderという拡張シャーディングAPIを使用してシャーディング・キーを指定することによって、特定のシャードへの接続を取得します。

大まかに言うと、アプリケーションがシャード・データベースと連携するようにするには、次のステップに従う必要があります。

  1. シャード・ディレクタおよびグローバル・サービスが反映されるようにURLを更新します。

  2. プール・パラメータをプール・レベルおよびシャード・レベルで設定します。

    • setInitialPoolSize: UCPが起動されたときに作成される初期の接続数

    • setMinPoolSize: 実行時にプールによって維持される接続の最小数

    • setMaxPoolSize: 接続プールで許可される接続の最大数を設定するためのUCPプロパティ

    • setMaxConnectionsPerShard: シャードごとの最大接続数の設定

  3. createShardingKeyBuilderを使用してシャーディング・キー・オブジェクトを作成します。

  4. createConnectionBuilderを使用して接続を確立します。

  5. 特定のシャードのスコープ内でトランザクションを実行します。

例54-1 UCPシャーディングAPIを使用した接続の確立

シャーディング・キーを作成し、UCPシャーディングAPIコールを使用して接続を確立する方法を示すコード片を次に示します。

...

PoolDataSource pds =                                
     PoolDataSourceFactory.getPoolDataSource();
  
  // Set Connection Pool properties
pds.setURL(DB_URL);
pds.setUser("hr");  
pds.setPassword("****");
pds.setInitialPoolSize(10);
pds.setMinPoolSize(20);
pds.setMaxPoolSize(30);
                
// build the sharding key object

OracleShardingKey shardingKey = 
    pds.createShardingKeyBuilder() 
      .subkey("mary.smith@example.com", OracleType.VARCHAR2)
      .build(); 

  // Get an UCP connection for a shard
Connection conn = 
    pds.createConnectionBuilder()
     .shardingKey(shardingKey)
     .build();
...

例54-2 UCP接続プールを使用したシャード対応アプリケーション・コードの例

この例では、プール設定をプール・レベルおよびシャード・レベルで定義しています。

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import oracle.jdbc.OracleShardingKey;
import oracle.jdbc.OracleType;
import oracle.jdbc.pool.OracleDataSource;
import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceFactory;

public class MaxConnPerShard
{    
  public static void main(String[] args) throws SQLException
  {    
    String url = "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(HOST=shard-dir1)(PORT=3216)(PROTOCOL=tcp))(CONNECT_DATA=(SERVICE_NAME=shsvc.shpool.oradbcloud)(REGION=east)))";
    String user="testuser1", pwd = "testuser1";  
  
    int maxPerShard = 100, initPoolSize = 20;    

    PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
    pds.setConnectionFactoryClassName(OracleDataSource.class.getName());
    pds.setURL(url);
    pds.setUser(user);
    pds.setPassword(pwd);
    pds.setConnectionPoolName("testpool");
    pds.setInitialPoolSize(initPoolSize);    

    // set max connection per shard
    pds.setMaxConnectionsPerShard(maxPerShard);
    System.out.println("Max-connections per shard is: "+pds.getMaxConnectionsPerShard());
                
    // build the sharding key object
    int shardingKeyVal = 123;    
    OracleShardingKey sdkey = pds.createShardingKeyBuilder()
        .subkey(shardingKeyVal, OracleType.NUMBER)
        .build();

    // try to build maxPerShard connections with the sharding key
    Connection[] conns = new Connection[maxPerShard];
    for (int i=0; i<maxPerShard; i++)
    {      
      conns[i] = pds.createConnectionBuilder()
          .shardingKey(sdkey)
          .build();
    
Statement stmt = conns[i].createStatement();
      ResultSet rs = stmt.executeQuery("select sys_context('userenv', 'instance_name'), sys_context('userenv', 'chunk_id') from dual");
      while (rs.next()) {
        System.out.println((i+1)+" - inst:"+rs.getString(1)+", chunk:"+rs.getString(2));
      }
      rs.close();
      stmt.close();
    }      

    System.out.println("Try to build "+(maxPerShard+1)+" connection ...");
    try {
      Connection conn = pds.createConnectionBuilder()
          .shardingKey(sdkey)
          .build();

      Statement stmt = conn.createStatement();
      ResultSet rs = stmt.executeQuery("select sys_context('userenv', 'instance_name'), sys_context('userenv', 'chunk_id') from dual");
      while (rs.next()) {
        System.out.println((maxPerShard+1)+" - inst:"+rs.getString(1)+", chunk:"+rs.getString(2));
      }
      rs.close();
      stmt.close();

      System.out.println("Problem!!! could not build connection as max-connections per shard exceeded");
      conn.close();
    } catch (SQLException e) {
      System.out.println("Max-connections per shard met, could not build connection any more, expected exception: "+e.getMessage());
    }    
    for (int i=0; i<conns.length; i++)
    {
      conns[i].close();
    }        
  }
}

ODP.NETシャーディングAPI

シャード対応のアプリケーションは、ODP.NET API (OracleConnectionクラスのSetShardingKey(OracleShardingKey shardingKey, OracleShardingKey superShardingKey)インスタンス・メソッドなど)を使用してシャーディング・キーおよびスーパー・シャーディング・キーを指定することによって、特定のシャードへの接続を取得します。

大まかに言うと、.NETアプリケーションがシャード・データベースと連携するようにするには、次のステップを実行する必要があります。

  1. ODP.NET管理対象外ドライバを使用します。

    シャーディングは、ODP.NET接続プールを使用する場合もODP.NET接続プールを使用しない場合もサポートされます。各プールは、シャード・データベースの異なるシャードへの接続を保持できます。

  2. OracleShardingKeyクラスを使用して、シャーディング・キー、およびスーパー・シャーディング・キーの別のインスタンスを設定します。

  3. ODP.NETが指定したシャーディング・キーおよびスーパー・シャーディング・キーを使用する接続を返すことができるように、OracleConnection.Open()を呼び出す前に、OracleConnection.SetShardingKey()メソッドを呼び出します。

    これらのキーは、OracleConnectionがクローズ状態のときに設定する必要があります。そうしないと、例外がスローされます。

例54-3 ODP.NETを使用したシャード対応アプリケーション・コードの例

using System;
using Oracle.DataAccess.Client;
 
class Sharding
{
  static void Main()
  {
    OracleConnection con = new OracleConnection("user id=hr;password=hr;Data Source=orcl;");
    //Setting a shard key
    OracleShardingKey shardingKey = new OracleShardingKey(OracleDbType.Int32, 123);
    //Setting a second shard key value for a composite key
    shardingKey.SetShardingKey(OracleDbType.Varchar2, "gold");
    //Creating and setting the super shard key
    OracleShardingKey superShardingKey = new OracleShardingKey();
    superShardingKey.SetShardingKey(OracleDbType.Int32, 1000);
    
    //Setting super sharding key and sharding key on the connection
    con.SetShardingKey(shardingKey, superShardingKey);
    con.Open();

    //perform SQL query
  }
}

関連項目:

Oracle Shardingに対するJDBCのサポートの詳細は、Oracle Database JDBC開発者ガイドを参照してください

Oracle Shardingに対するUCPのサポートの詳細は、Oracle Universal Connection Pool開発者ガイドを参照してください

Oracle Shardingに対するODP.NETのサポートの詳細は、Microsoft Windows用Oracle Data Provider for .NET開発者ガイドを参照してください

シャードを使用するためのOCIインタフェースの詳細は、Oracle Call Interfaceプログラマーズ・ガイドを参照してください

54.2 SDBでのプロキシ・ルーティングを介した問合せおよびDML

シャーディングでは、シャーディング・キーを指定しない問合せのルーティングがサポートされます。これにより、データベース・アプリケーションが柔軟になり、問合せが実行されるシャードを指定することなく、表がシャーディングまたは複製されているシステムでSQL文(SELECTおよびDMLを含む)を実行できるようになります。

次のトピックでは、プロキシ・ルーティングについてさらに詳しく説明します。

54.2.1 シャード・データベースでのプロキシ・ルーティングについて

プロキシ・ルーティングは、開発者の利便性のための補助的な使用パターンです。これを使用するには、コーディネータに対して接続を確立する必要があります。

Oracle Database 12.2では、シャード・カタログ・データベースにはコーディネータ・データベースの役割があります。コーディネータは、シャード・トポロジのメタデータを使用し、シャード・データベースの問合せ処理をサポートします。SQLコンパイラは、関連するシャードを自動的に識別し、関与するすべてのシャード間での問合せの実行を調整します。コーディネータに対してセッションが確立されると、変更を必要とせずにSQL問合せおよびDMLが実行されます。

プロキシ・ルーティングは次のシナリオに適しています。

  • 接続中にアプリケーションがシャーディング・キーを渡すことができない場合

  • アプリケーションが複数のシャードに存在するシャード表のデータにアクセスする必要がある場合

  • レポート(販売データの集計など)に一般的に使用されるSQL問合せ

コーディネータを使用したルーティングでは、接続中にシャーディング・キー値を渡すことなく、アプリケーションがSQL文を発行できます。コーディネータのSQLコンパイラは問合せを分析して問合せの断片にリライトし、それらが関与するシャードに送信されて実行されます。問合せは、関与するシャードでほとんどの問合せ処理が行われて、コーディネータによって集計されるようにリライトされます。要するに、シャードはコーディネータによって実行された問合せの計算ノードとして動作します。計算がデータのあるシャードにプッシュされるため、シャードとコーディネータの間のデータの移動が減少します。また、コーディネータの処理負荷を軽減するために、シャードのリソースを可能なかぎり効率的に活用できます。

アプリケーションでワークロードを直接ルーティングとプロキシ・ルーティングに分離することをお薦めします。これらのワークロードのために、個別の接続プールを作成する必要があります。

54.2.2 Oracle Shardingコーディネータ

Oracle Shardingコーディネータ・データベースには、シャード・トポロジのメタデータが含まれており、シャード・データベースの問合せ処理をサポートします。

コーディネータへの接続

マルチシャード問合せを実行するには、シャード・カタログ・データベースでGDS$CATALOGサービスを使用してコーディネータに接続します。

sqlplus app_schema/app_schema@shardcatvm:1521/GDS\$CATALOG.oradbcloud

コーディネータの高可用性

コーディネータを使用できない場合、プロキシ・ルーティング・ベースのワークロードに影響します。ファスト・スタート・フェイルオーバーを有効にして最大可用性保護モード(データ損失のないフェイルオーバー)でData Guardを使用してコーディネータを保護することをお薦めします。コーディネータはさらなる可用性およびスケーラビリティのためにオプションでOracle RAC対応にすることができます。

コーディネータが使用できなくても、直接ルーティングを使用したワークロードには影響しません。

コーディネータ・データベースのサイズ設定

シャード・カタログおよびコーディネータは次の重要な情報をホストします。

  • シャード・データベース・トポロジのメタデータ

  • シャード・アプリケーションのスキーマ

  • 重複表のマスター・コピー

メタデータおよびスキーマのサイズは通常どおりです。ただし、コーディネータのサイズを決定するときに、重複表の数およびそれらが占有する領域を計画する必要があります。

それに加えて、CPU、I/Oおよびメモリーが集中的に使用されることがあるプロキシ・ルーティングを処理するために、SQL問合せおよび処理されるデータ量に基づいて、コーディネータのサイズを設定する必要もあります。

54.2.3 プロキシ・ルーティングを使用した問合せおよびDML

プロキシ・ルーティングを使用すると、データを集計したり、複数のシャードに関するレポートを作成したりできます。また、データベース・アプリケーションが柔軟になり、問合せが実行されるシャーディング・キーを(接続中に)指定することなく、表がシャーディングまたは複製されているシステムでSQL文(SELECT、DMLを含む)を実行できるようになります。

どちらのユースケースでも、ユーザーは直接ルーティングと比べて低いレベルのパフォーマンスを受け入れます。

シャード・データベース(SDB)には、2つのタイプの表(シャード表および重複表)があります。

シャード表はシャーディング・キーによって等価パーティション化されます。

S=S1 U S2 UU Sn

重複表はすべてのシャードで同一です。

R = R1 = … = Rn

SDBのプロキシ・ルーティングは、アプリケーションが関連するシャードを指定することなく、シャード表および重複表のデータにアクセスする通常のSQL問合せを実行するための透過的なメカニズムを提供します。SQLコンパイラは、関連するシャードを自動的に識別し、関与するすべてのシャード間での問合せの実行を調整します。コーディネータとシャードの間の通信のために、データベース・リンクが使用されます。

大まかに言うと、コーディネータは各受信問合せQを2つの問合せ(CQおよびSQ)で構成される分配形式にリライトします。ここで、SQ (シャード問合せ)は関与する各シャードで実行されるQの部分であり、CQ (コーディネータ問合せ)はコーディネータ・シャードで実行される部分です。

Q  =>  CQ ( Shard_Iterator( SQ ) )

次の例は、集計問合せQ1をシャード間実行のためにQ1'にリライトしています。

Q1 : SELECT COUNT(*) FROM customers

Q1’: SELECT SUM(sc) FROM (Shard_Iterator(SELECT COUNT(*) sc FROM s1 (i) ))

このプロセスには2つの重要な要素があります。(1)関連するシャードを識別し、(2)分配形式でシャードごとに繰り返すように問合せをリライトすることです。

コーディネータ・データベースでの問合せのコンパイル中に、問合せコンパイラはシャーディング・キーに対する述語を分析し、関与するシャード(つまり、問合せで参照されるシャード表の行があるシャード)を識別するために使用できる述語を抽出します。残りのシャードは除外されたシャードと呼ばれます。

関与するシャードが1つのみ識別された場合は、問合せ全体がそのシャードにルーティングされて、すべてが実行されます。これは単一シャード問合せと言います。関与する複数のシャードがある場合、その問合せはマルチシャード問合せと呼ばれ、リライトされます。リライト処理では、問合せによって計算される式および問合せの形態が考慮されます。

54.2.4 単一シャード問合せのためのプロキシ・ルーティング

単一シャード問合せ(SSQ)は、1つのシャードのデータのみをスキャンする必要があり、他のシャードを検索する必要がない問合せです。

SSQは、特定のシャードに接続してそのシャードに問合せを発行するクライアントに似ています。このシナリオでは、問合せ全体が関与する単一のシャードで実行され、コーディネータは処理された行をクライアントに返すだけです。コーディネータ上のプランは、リモート・マップ・カーソルに似ています。

たとえば、次の問合せは、顧客123のデータがshard1にあるため、shard1にすべてマップされます。シャードでの実行の単位は問合せ全体です。

Q1: SELECT count(*) 
    FROM customers c, orders o 
    WHERE c.custno = o.custno and 
          c.custno = 123;

SSQには、問合せのコンパイル時(リテラル)または問合せ開始時(バインド)に判明する1つのシャードにのみマップするシャード・キーの条件が含まれています。問合せは該当するシャードですべて実行されます。SSQでは、SELECT、UPDATE、DELETEおよびINSERTを使用できます。MERGE/UPSERTはサポートされません。

SSQでは次のものがサポートされます。

  • 等価およびINリスト(Area = 'West'など)

  • リテラル、バインド、またはリテラルとバインドの式を含む次のような条件

    Area = :bind
    
    Area = CASE :bind <10 THEN ‘West’ ELSE ‘East’ END
  • SELECTUPDATEDELETEおよびINSERT

54.2.5 マルチシャード問合せのためのプロキシ・ルーティング

マルチシャード問合せでは、複数のシャードでデータをスキャンする必要があり、各シャードでの処理は他のシャードから独立しています。

マルチシャード問合せは、複数のシャードにマップされ、結果をクライアントに送信する前に、コーディネータが処理する必要がある場合があります。たとえば、次の問合せは各顧客によって発注されたオーダー数をフェッチします。

Q2: SELECT count(*), c.custno 
    FROM customers c, orders o 
    WHERE c.custno = o.custno
    GROUP BY c.custno;

この問合せは、コーディネータによって次のように変換されます。

Q3: SELECT sum(count_col), custno 
    FROM (SELECT count(*) count_col, c.custno 
          FROM customers c, orders o 
          WHERE c.custno = o.custno
          GROUP BY c.custno)
    GROUP BY custno;

インライン問合せブロックは、リモート・マップ問合せブロックのように各シャードにマップされます。コーディネータは、すべてのシャードからの結果セットに対して、さらなる集計およびGROUP BYを実行します。各シャードでの実行の単位はインライン問合せブロックです。

Oracle Database 12cリリース2では、マルチシャード問合せはSELECT文のみがサポートされます。問合せは、単一のシャード(等価フィルタの場合)またはすべてのシャード(シャーディング・キーにフィルタ述語がない場合)にアクセスできます。

54.2.6 プロキシ・ルーティングの回復力

可用性およびスケーラビリティのために、ファスト・スタート・フェイルオーバーを持つData Guardを使用したり、オプションでOracle RAC対応にすることによって、コーディネータを保護することをお薦めします。

コーディネータの障害は、コーディネータを介してルーティングされるマルチシャード問合せおよび単一シャード問合せに影響します。問合せの実行中の障害のシナリオ、およびプロキシ・ルーティングの予期される動作を次に示します。

  • 関与するシャードが停止している場合、コーディネータは同じデータを使用してその問合せを別のシャードに送信します。

  • 関与するシャードに対して問合せを実行しているときに障害が発生した場合、ユーザーはエラーを受け取ります。

54.2.7 プロキシ・ルーティングでサポートされる問合せの形態

Oracle Database 12cリリース2では、マルチシャード問合せのサポートにいくつかの制限があります。問合せに関連する表のタイプに基づく制限や使用されているSQL構造に基づく制限があります。

結合(たとえば、2つのシャード表の結合)を含む問合せを正常に実行するには、次の2つの条件のいずれかを満たしている必要があります。

  • すべての表がシャーディング・キーに対する等価フィルタを使用して結合されている。

  • すべての表にシャーディング・キーに対するフィルタがあり、同じシャードが選択される。

シャード表と重複表を結合する問合せでは、任意の比較演算子(= < > <= >=)または任意の結合式を使用して列を問い合せることができます。

重複表のみが関係する問合せ

重複表のみが関係する問合せの場合、問合せの形態に制限はありません。問合せはコーディネータで実行されます。

シャード表のみが関係する問合せ

単一表の問合せの場合、問合せにはシャードを限定するシャーディング・キーに対する等価フィルタを指定できます。結合問合せの場合は、すべての表がシャーディング・キーに対する等価フィルタを使用して結合される必要があります。様々なサポートされる結合パターンおよびサポートされない結合パターンを次に示します。

サポートされている

  • シャーディング・キーのみを使用する等価結合の内部結合

    SELECT … FROM s1 INNER JOIN s2 ON s1.sk=s2.sk 
    WHERE any_filter(s1) AND any_filter(s2)
    
  • シャーディング・キーのみを使用する左外部結合

    SELECT … FROM s1 LEFT OUTER JOIN s2 ON s1.sk=s2.sk
  • 右外部結合(左外部結合と同じ)

    SELECT … FROM s1 RIGHT OUTER JOIN s2 ON s1.sk=s2.sk
  • シャーディング・キーのみを使用する完全外部結合(等価結合を必要とするネイティブが有効な場合のみ)

    SELECT … FROM s1 FULL OUTER JOIN s2 ON s1.sk=s2.sk
    WHERE any_filter(s1) AND any_filter(s2)
    

サポートされていない

  • シャーディング・キー以外を使用するセミ結合(EXISTS)

  • アンチ結合(NOT EXISTS)

シャード表および重複表が関係する問合せ

このタイプの問合せは、シャーディング・キーに対する述語に基づくSSQまたはMSQです。唯一の違いは、各シャードで重複している非シャード表が問合せに含まれていることです。

シャード表と重複表の結合では、任意の列で、任意の比較演算子(= < > <= >=)または任意の結合式を使用できます。様々なサポートされる結合パターンおよびサポートされない結合パターンを次に示します。

サポートされている

  • 内部結合

    SELECT … FROM s1 INNER JOIN r1 ON any_join_condition(s1,r1) 
    WHERE any_filter(s1) AND any_filter(r1)
    
  • 左/右外部結合

    条件: シャード表は次のようなNULLで補完される表である必要があります

    • シャード表がLEFT OUTER JOINの最初の表である

      SELECT … FROM s1 LEFT OUTER JOIN r1 ON any_join_condition(s1,r1) 
      WHERE any_filter(s1) AND any_filter(r1)
      
      SELECT … FROM r1 LEFT OUTER JOIN s1 ON any_join_condition(s1,s2) 
      AND any_filter(r1) AND filter_one_shard(s1)
    • シャード表がRIGHT OUTER JOINの2番目の表である

      SELECT … FROM r1 RIGHT OUTER JOIN s1 ON any_join_condition(s1,r1) 
      WHERE any_filter(s1) AND any_filter(r1)
      
      SELECT … FROM s1 RIGHT OUTER JOIN r1 ON any_join_condition(s1,s2) 
      AND filter_one_shard(s1) AND any_filter(r1)
      
  • 完全外部結合

    条件: シャーディング・キーに対するフィルタ述語およびネイティブな完全外部結合を介して、シャード表が単一のシャードに限定されます

    SELECT … FROM s1 FULL OUTER JOIN r1 ON s1.sk=s2.sk
    WHERE any_filter(s1) AND any_filter(s2)
    
  • セミ結合(EXISTS)

    条件: 重複表が副問合せにあるか、シャード表が副問合せにあり、シャーディング・キーに対するフィルタを使用して単一のシャードに限定されます

    SELECT … FROM s1 EXISTS 
    (SELECT 1 FROM r1 WHERE r1.anykey=s1.anykey)
    
    SELECT … FROM r1 EXISTS 
    (SELECT 1 FROM s1 WHERE r1.anykey=s1.anykey and filter_one_shard(s1))
    
  • アンチ結合(NOT EXISTS)

    条件: 重複表が副問合せにある必要があります

    SELECT … FROM s1 NOT EXISTS 
    (SELECT 1 FROM r1 WHERE r1.anykey=s1.anykey)	
    

サポートされていない

  • 左/右外部結合

    重複表がLEFT OUTER JOINの最初の表であるか、シャード表が最初の表でシャーディング・キーに対するフィルタ述語に基づいて単一のシャードにマップされます。

    SELECT … FROM r1 LEFT OUTER JOIN s1 ON any_join_condition(s1,s2) 
    AND any_filter(r1) AND any_filter(s1)
    

    重複表がRIGHT OUTER JOINの2番目の表であるか、シャード表が2番目の表でシャーディング・キーに対するフィルタ述語に基づいて単一のシャードにマップされます。

    SELECT … FROM s1 RIGHT OUTER JOIN r1 ON any_join_condition(s1,s2) 
    AND any_filter (s1) AND any_filter(r1)
    
  • 完全外部結合

    複数のシャードへのアクセスが必要となるシャード表

    SELECT … FROM s1 FULL OUTER JOIN r1 ON s1.non_sk=s2.non_sk
    WHERE any_filter(s1) AND any_filter(s2)
    
  • セミ結合(EXISTS)

    複数のシャードへのアクセスが必要となる副問合せのシャード表。

    SELECT … FROM r1 EXISTS 
    (SELECT 1 FROM s1 WHERE r1.anykey=s1.anykey)
    
  • アンチ結合(NOT EXISTS)

    シャード表が副問合せにあります

    SELECT … FROM r1 NOT EXISTS 
    (SELECT 1 FROM s1 WHERE r1.anykey=s1.anykey

集計関数

次の集計はプロキシ・ルーティングによってサポートされます。

  • COUNT

  • SUM

  • MIN

  • MAX

  • AVG

マルチシャード問合せとグローバルCR

マルチシャード問合せでは、すべてのシャードで最も大きい共通SCNで問合せを発行することによって、グローバルな読込み一貫性(CR)を維持する必要があります。

トランザクション

1つのシャードのみに影響するDML文はサポートされます。例:

update S1 set col = … where sk = <constant>;

複数のシャードに影響するDML文はサポートされません。例:

update S1 set col = …;

1つのトランザクション内では、複数の単一シャードDMLを異なるシャードに対して実行できます。例:

insert into S1 values (…);
Update S1 set col = … where sk = constant;
Delete S1 where sk = constant;
Commit;

マルチシャードDMLの場合、コーディネータはデータベース・リンクを使用して分散トランザクションを開始し、2フェーズ・コミットを実行して分散トランザクションの一貫性を保証します。インダウト・トランザクションの場合、データベース管理者はそれを手動でリカバリする必要があります。

プロキシ・ルーティング用の実行計画

Oracle Database 12cリリース2 (12.2.0.1)では、シャード問合せの計画には、コーディネータの計画のみが表示されます。問合せに関するシャードの計画を参照するには、シャードに接続する必要があります。シャードに対する問合せのSQL IDはコーディネータに対する元の問合せのSQL IDとは異なるため、シャード問合せテキストはコーディネータのSQL IDとともに埋め込まれるので、シャード・ユーザーは、SQLテキストのコメントとして元のSQLのSQL IDを持つSQLを探す必要があります。

SQL> explain plan for select count(*) from employees;

-----------------------------------------------
| Id  | Operation         | Name              |
-----------------------------------------------
|   0 | SELECT STATEMENT  |                   |
|   1 |  SORT AGGREGATE   |                   |
|   2 |   VIEW            | VW_SHARD_B4851255 |
|   3 |    SHARD ITERATOR |                   |
|   4 |     REMOTE        |                   |
-----------------------------------------------
Remote SQL Information (identified by operation id):
----------------------------------------------------
   4 - EXPLAIN PLAN INTO PLAN_TABLE@! FOR
       SELECT COUNT(*) FROM "EMPLOYEES" "A1" /* coord_sql_id=3g18nvrpt0a8p */

シャード問合せ間でのヒントの受け渡し

コーディネータに対する元の問合せで指定したヒントは、シャードに伝播されます。

シャード問合せ間での実行速度低下のトレースとトラブルシューティング

クエリー・リライトおよびシャード・プルーニングをトレースするには、コーディネータに対してトレース・イベントshard_sqlを設定します。観測される一般的なパフォーマンス問題の1つは、シャーディングの一定の制限により、グループ化基準がシャードにプッシュされない場合です。考えられるすべての操作がシャードにプッシュされ、シャードからの結果を統合するためのコーディネータでの処理が最低限であるかどうかを確認します。