シングルトンデータベースのクエリ操作と比較すると、分散データクエリには多くの技術的な問題があります。
この記事では、Mysql サブデータベース サブテーブルと Elasticsearch Join クエリの実装アイデアを記録し、分散シーン データ処理の設計スキームを理解します。
この記事では、一般的に使用されるリレーショナル データベース MySQL のサブデータベースおよびサブテーブル結合分析から非リレーショナル ElasticSearch までの結合実装戦略を分析します。Join の詳細な実装メカニズムを段階的に説明します。
①Mysqlサブデータベースサブテーブル結合クエリシナリオ
サブデータベースとサブテーブルのシナリオで、クエリ文をどのように分散するか、データをどのように整理するか。NoSQL データベースと比較すると、Mysql は SQL 仕様の範囲内で分散シナリオに適応するのが比較的簡単です。
sharding-jdbc ミドルウェア ソリューションに基づいて、設計アイデア全体を理解します。
シャーディング-jdbc
- sharding-jdbc は元のデータソースのプロキシとして機能し、jdbc 仕様を実装してサブデータベースとサブテーブルの配布とアセンブリを完了します。アプリケーション層は認識しません。
- 実行プロセス: SQL 分析 => 実行プログラムの最適化 => SQL ルーティング => SQL 書き換え => SQL 実行 => 結果のマージ
io.shardingsphere.core.executor.ExecutorEngine#execute
- Join ステートメントの分析により、SQL を分散するインスタンス ノードが決定されます。SQLルーティングに対応します。
- SQL の書き換えとは、元の (論理) テーブル名を実際のシャード テーブル名に変更することです。
- 複雑な場合、結合クエリ分散の最大実行時間 = データベース インスタンス × テーブル A のシャード数 × テーブル B のシャード数
コードインサイト
サンプルコードプロジェクト: [email protected]:cluoHeadon/sharding-jdbc-demo.git
/**
* 执行查询 SQL 切入点,从这里可以完整 debug 执行流程
* @see ShardingPreparedStatement#execute()
* @see ParsingSQLRouter#route(String, List, SQLStatement) Join 查询实际涉及哪些表,就是在路由规则里匹配得出来的。
*/
public boolean execute() throws SQLException {
try {
// 根据参数(决定分片)和具体的SQL 来匹配相关的实际 Table。
Collection<PreparedStatementUnit> preparedStatementUnits = route();
// 使用线程池,分发执行和结果归并。
return new PreparedStatementExecutor(getConnection().getShardingContext().getExecutorEngine(), routeResult.getSqlStatement().getType(), preparedStatementUnits).execute();
} finally {
JDBCShardingRefreshHandler.build(routeResult, connection).execute();
clearBatch();
}
}
SQLルーティングポリシー
SQL 印刷を有効にして、実際に配布および実行された SQL を視覚的に確認します。
# 打印的代码,就是在上述route 得出 ExecutionUnits 后,打印的
sharding.jdbc.config.sharding.props.sql.show=true
sharding-jdbc には、さまざまな SQL ステートメントに応じてさまざまなルーティング戦略があります。私たちが注目する結合クエリは、実際には次の 2 つの戦略に関連しています。
- StandardRoutingEngine バインディング テーブル モード
- ComplexRoutingEngine 最も複雑なケースは、デカルト結合の関連付けです。
-- 参数不明,不能定位分片的情况
select * from order o inner join order_item oi on o.order_id = oi.order_id
-- 路由结果
-- Actual SQL: db1 ::: select * from order_1 o inner join order_item_1 oi on o.order_id = oi.order_id
-- Actual SQL: db1 ::: select * from order_1 o inner join order_item_0 oi on o.order_id = oi.order_id
-- Actual SQL: db1 ::: select * from order_0 o inner join order_item_1 oi on o.order_id = oi.order_id
-- Actual SQL: db1 ::: select * from order_0 o inner join order_item_0 oi on o.order_id = oi.order_id
-- Actual SQL: db0 ::: select * from order_1 o inner join order_item_1 oi on o.order_id = oi.order_id
-- Actual SQL: db0 ::: select * from order_1 o inner join order_item_0 oi on o.order_id = oi.order_id
-- Actual SQL: db0 ::: select * from order_0 o inner join order_item_1 oi on o.order_id = oi.order_id
-- Actual SQL: db0 ::: select * from order_0 o inner join order_item_0 oi on o.order_id = oi.order_id
②Elasticsearch Joinクエリシナリオ
まず、NoSQL データベースの場合、Join クエリが必要であり、使用シナリオと用途に問題があるかどうかを検討できます。
したがって、必然的に、一部のシナリオではこの機能が必要になります。Join クエリの実装は SQL エンジンに近いものです。
elasticsearch-sql コンポーネントのソリューションに基づいて、一般的な実装のアイデアを理解します。
elasticsearch-sql
- これは、http サービスを提供することで SQL のようなクエリ関数を実装する elasticsearch プラグインです。elasticsearch の上位バージョンにはすでにこの機能があります⭐
- elasticsearch には結合クエリの機能がないため、SQL 結合関数を実装するには、結合アルゴリズムを含むさらに低レベルの関数を提供する必要があります。
コードインサイト
ソースアドレス: [email protected]:NLPchina/elasticsearch-sql.git
/**
* Execute the ActionRequest and returns the REST response using the channel.
* @see ElasticDefaultRestExecutor#execute
* @see ESJoinQueryActionFactory#createJoinAction Join 算法选择
*/
@Override
public void execute(Client client, Map<String, String> params, QueryAction queryAction, RestChannel channel) throws Exception{
// sql parse
SqlElasticRequestBuilder requestBuilder = queryAction.explain();
// join 查询
if(requestBuilder instanceof JoinRequestBuilder){
// join 算法选择。包括:HashJoinElasticExecutor、NestedLoopsElasticExecutor
// 如果关联条件为等值(Condition.OPEAR.EQ),则使用 HashJoinElasticExecutor
ElasticJoinExecutor executor = ElasticJoinExecutor.createJoinExecutor(client,requestBuilder);
executor.run();
executor.sendResponse(channel);
}
// 其他类型查询 ...
}
③参加するだけではない
結合アルゴリズム
- よく使用される 3 つの結合アルゴリズム: ネストされたループ結合、ハッシュ結合、マージ結合
- MySQL は NLJ またはそのバリアントのみをサポートし、バージョン 8.0.18 以降はハッシュ結合をサポートします。
- NLJ は 2 つのネストされたループに相当します。最初のテーブルは外部ループとして使用され、2 番目のテーブルは内部ループとして使用されます。外部ループの各レコードは内部ループのレコードと比較され、一致するデータが取得されます。状況は最終的に記録されます。
- ハッシュ結合は
build
構築フェーズとprobe
検出フェーズの 2 つのフェーズに分かれています。 - Explain を使用すると、MySQL が使用する結合アルゴリズムを確認できます。必須の構文キーワード: FORMAT=JSON または FORMAT=Tree
EXPLAIN FORMAT=JSON
SELECT * FROM
sale_line_info u
JOIN sale_line_manager o ON u.sale_line_code = o.sale_line_code;
{
"query_block": {
"select_id": 1,
// 使用的join 算法: nested_loop
"nested_loop": [
// 涉及join 的表以及对应的 key,其他的信息与常用explain 类似
{
"table": {
"table_name": "o",
"access_type": "ALL"
}
},
{
"table": {
"table_name": "u",
"access_type": "ref"
}
}
]
}
}
Elasticsearch ネスト型
Elasticsearch のビジネス データと使用シナリオを分析するための別のオプションは、関連情報を含むドキュメントを直接保存することです。Elasticsearch では、クエリと取得が完全なドキュメントの形式で提供され、結合関連テクノロジの使用が完全に回避されます。
これには、関連付けが属性型のデータであるか共通型のデータであるか、関連付けられるデータのサイズ、関連付けられるデータの更新頻度などが含まれます。これらはすべて、Nested タイプを使用するときに考慮する必要がある要素です。
詳しい使用方法はインターネットや公式サイトに記載されているので割愛します。
これで、Nested 型を使用するビジネス関数が完成しました。これにより、クエリと最適化のプロセスにおける非常に大きな問題が解決されました。
要約する
動作原理の分析を通じて、私たちは動作プロセスを明確かつ深く理解しています。
ミドルウェアの最適化とテクノロジーの選択はより目的を持っており、使用はより慎重かつ慎重になります。
フィルター条件を明確にし、フィルター範囲を小さくし、制限値データを使用すると、計算コストが削減され、パフォーマンスが向上します。
参考
著者: JD Logistics Yang Pan
出典: JD Cloud 開発者コミュニティ