분산 데이터베이스 조인 쿼리 설계 및 구현 분석 | JD Cloud 기술 팀

단일 데이터베이스의 쿼리 작업과 비교할 때 분산 데이터 쿼리는 많은 기술적 어려움이 있습니다.

이 기사는 Mysql 하위 데이터베이스 하위 테이블 및 Elasticsearch 조인 쿼리의 구현 아이디어를 기록하고 분산 장면 데이터 처리의 설계 체계를 이해합니다.
이 기사는 일반적으로 사용되는 관계형 데이터베이스 MySQL의 하위 데이터베이스 및 하위 테이블 조인 분석에서 비 관계형 ElasticSearch에 대한 조인 구현 전략을 분석합니다. 조인의 단계별 심층 구현 메커니즘.

① 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 문에 따라 다른 라우팅 전략을 갖습니다. 우리가 집중하는 조인 쿼리는 실제로 다음 두 가지 전략과 관련이 있습니다.

  • 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 조인 쿼리 시나리오

우선 NoSQL 데이터베이스의 경우 Join 쿼리가 필요하며 사용 시나리오 및 사용에 문제가 없는지 고려할 수 있습니다.

그런 다음 필연적으로 일부 시나리오에는 이 기능이 필요합니다. 조인 쿼리의 구현은 SQL 엔진에 더 가깝습니다.

elasticsearch-sql 구성 요소의 솔루션을 기반으로 일반적인 구현 아이디어를 이해합니다.

탄력적 검색-sql

  • http 서비스를 제공하여 SQL과 같은 질의 기능을 구현한 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);
    }
    // 其他类型查询 ...
}

③가입 그 이상

조인 알고리즘

  • 일반적으로 사용되는 세 가지 조인 알고리즘: 중첩 루프 조인, 해시 조인, 병합 조인
  • MySQL은 NLJ 또는 그 변형만 지원하며 버전 8.0.18 이후의 해시 조인을 지원합니다.
  • NLJ는 두 개의 중첩된 루프에 해당합니다. 첫 번째 테이블은 외부 루프로 사용되고 두 번째 테이블은 내부 루프로 사용됩니다. 외부 루프의 각 레코드는 내부 루프의 레코드와 비교되며 충족하는 데이터는 조건이 최종적으로 기록됩니다.
  • build 해시 조인은 구성 단계와  감지 단계의 두 단계로 나뉩니다  probe .
  • 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 클라우드 개발자 커뮤니티

{{o.이름}}
{{이름}}

추천

출처my.oschina.net/u/4090830/blog/9907983