로컬 파티션을 먼저 읽은 다음 로컬에서 찾을 수 없는 경우 전역 읽기

다음은 로컬 읽기의 또 다른 경우입니다. 나는 customer_id를 가지고 있지만 그녀의 나라를 모릅니다. 그러나 그녀의 데이터가 있는 곳에 내가 연결되어 있을 가능성이 높습니다. 유럽 ​​은행의 고객이 아마도 유럽에서 연결하는 것처럼 생각하십시오. 이 경우 대기 시간이 짧은 쿼리를 원합니다. 예를 들어 고객이 여행 중이고 미국에서 쿼리하는 경우 은행 계좌가 유럽에 있음을 알면 대기 시간이 더 길어질 수 있습니다.

와 동일한 데이터에서 이 데모를 실행하고 있습니다. 모든 DDL과 DML은 . 로컬 테이블에서 읽기 위해 yb_is_local_table(tableoid)를 사용했습니다.

사용자 지역에 연결



사용자9f0345c1-ff88-477d-8f87-b6ae3717ba37earth 지역(포트 5433)에 있습니다.


yugabyte=# \c - - - 5433

psql (13.5, server 11.2-YB-2.15.1.0-b0)
You are now connected to database "yugabyte" as user "postgres".

yugabyte=# show listen_addresses;

       listen_addresses
------------------------------
 yb-tserver-0.base.earth.star
(1 row)

yugabyte=# select * from customers
           where id in ('9f0345c1-ff88-477d-8f87-b6ae3717ba37','3a890dfc-2a99-4ef4-9939-9fea1c9241ad')
           and yb_is_local_table(tableoid);

                  id                  | planet | info
--------------------------------------+--------+------
 9f0345c1-ff88-477d-8f87-b6ae3717ba37 | earth  | 1465
(1 row)




내 사용자가 어디에 있는지 확인하기 위해 이 작업을 수행했지만 문제가 해결되지 않았습니다. 올바른 영역에 연결하고 로컬 파티션을 쿼리하려면 사용자 영역을 알아야 합니다.

유니온 올



사용자가 한 지역에만 있을 수 있다는 것을 알고 있습니다. 여기에서 사용된 PostgreSQL의 선언적 파티셔닝에는 글로벌 인덱스가 없기 때문에 데이터베이스에서 이를 보장하지 않습니다. 기본 키에는 지역(내 예에서는 planet)이 포함됩니다.

yugabyte=# \d customers
           Partitioned table "public.customers"
 Column | Type | Collation | Nullable |      Default
--------+------+-----------+----------+-------------------
 id     | uuid |           | not null | gen_random_uuid()
 planet | text |           | not null |
 info   | text |           |          |
Partition key: LIST (planet)
Indexes:
    "customers_pkey" PRIMARY KEY, lsm (id HASH, planet ASC)
Number of partitions: 3 (Use \d+ to list them.)


그러나 내가 그들을 고유하게 생성했다는 것을 알고 있다면 하나의 ID에 대한 내 쿼리가 하나의 행만 반환한다는 사실에 의존할 수 있습니다.

select * from customers 
 where id='9f0345c1-ff88-477d-8f87-b6ae3717ba37'
 and yb_is_local_table(tableoid)
union all
select * from customers 
 where id='9f0345c1-ff88-477d-8f87-b6ae3717ba37'
and not yb_is_local_table(tableoid)
limit 1;

                  id                  | planet | info
--------------------------------------+--------+------
 9f0345c1-ff88-477d-8f87-b6ae3717ba37 | earth  | 1465


earth에 연결된 경우 실행을 살펴보겠습니다.

\c - - - 5433

explain (costs off, analyze, summary off)
select * from customers 
 where id='9f0345c1-ff88-477d-8f87-b6ae3717ba37'
 and yb_is_local_table(tableoid)
union all
select * from customers 
 where id='9f0345c1-ff88-477d-8f87-b6ae3717ba37'
 and not yb_is_local_table(tableoid)
limit 1;

                                                      QUERY PLAN
----------------------------------------------------------------------------------------------------------------------
 Limit (actual time=0.653..0.655 rows=1 loops=1)
   ->  Append (actual time=0.614..0.614 rows=1 loops=1)
         ->  Append (actual time=0.614..0.614 rows=1 loops=1)
               ->  Index Scan using customers_earth_pkey on customers_earth (actual time=0.613..0.613 rows=1 loops=1)
                     Index Cond: (id = '9f0345c1-ff88-477d-8f87-b6ae3717ba37'::uuid)
                     Filter: yb_is_local_table(tableoid)
         ->  Append (never executed)
               ->  Index Scan using customers_earth_pkey on customers_earth customers_earth_1 (never executed)
                     Index Cond: (id = '9f0345c1-ff88-477d-8f87-b6ae3717ba37'::uuid)
                     Filter: (NOT yb_is_local_table(tableoid))
               ->  Index Scan using customers_mars_pkey on customers_mars (never executed)
                     Index Cond: (id = '9f0345c1-ff88-477d-8f87-b6ae3717ba37'::uuid)
                     Filter: (NOT yb_is_local_table(tableoid))
               ->  Index Scan using customers_moon_pkey on customers_moon (never executed)
                     Index Cond: (id = '9f0345c1-ff88-477d-8f87-b6ae3717ba37'::uuid)
                     Filter: (NOT yb_is_local_table(tableoid))



첫 번째 분기인 읽기customers_earth(로컬 분기)만 실행되어 rows=1를 반환하고 나머지 분기는 건너뛰었습니다((never executed)).
moon에서 실행할 때도 동일합니다.

\c - - - 5434

explain (costs off, analyze, summary off)
select * from customers 
 where id='9f0345c1-ff88-477d-8f87-b6ae3717ba37'
 and yb_is_local_table(tableoid)
union all
select * from customers 
 where id='9f0345c1-ff88-477d-8f87-b6ae3717ba37'
and not yb_is_local_table(tableoid)
limit 1;

                                                      QUERY PLAN
----------------------------------------------------------------------------------------------------------------------
 Limit (actual time=1.122..1.124 rows=1 loops=1)
   ->  Append (actual time=1.121..1.121 rows=1 loops=1)
         ->  Append (actual time=0.481..0.481 rows=0 loops=1)
               ->  Index Scan using customers_moon_pkey on customers_moon (actual time=0.480..0.480 rows=0 loops=1)
                     Index Cond: (id = '9f0345c1-ff88-477d-8f87-b6ae3717ba37'::uuid)
                     Filter: yb_is_local_table(tableoid)
         ->  Append (actual time=0.640..0.640 rows=1 loops=1)
               ->  Index Scan using customers_earth_pkey on customers_earth (actual time=0.639..0.639 rows=1 loops=1)
                     Index Cond: (id = '9f0345c1-ff88-477d-8f87-b6ae3717ba37'::uuid)
                     Filter: (NOT yb_is_local_table(tableoid))
               ->  Index Scan using customers_mars_pkey on customers_mars (never executed)
                     Index Cond: (id = '9f0345c1-ff88-477d-8f87-b6ae3717ba37'::uuid)
                     Filter: (NOT yb_is_local_table(tableoid))
               ->  Index Scan using customers_moon_pkey on customers_moon customers_moon_1 (never executed)
                     Index Cond: (id = '9f0345c1-ff88-477d-8f87-b6ae3717ba37'::uuid)
                     Filter: (NOT yb_is_local_table(tableoid))
(16 rows)


현재 있는 첫 번째 분기customers_moon(로컬 분기)는 행(rows=0)을 반환하지 않았고 두 번째 분기는 행을 반환할 때까지 분할 후 분할 실행되었습니다.

이것은 우리의 목표에 부합합니다. 사용자가 현지에 있을 때는 짧은 대기 시간, 여행 중인 경우에는 더 높은 대기 시간입니다.

그러나 두 가지 문제가 있습니다.
  • 로컬 파티션을 두 번 읽을 수 있습니다(하나는 로컬 파티션이고 다른 하나는 글로벌 브랜치에서 처음 읽는 경우)
  • 우리는 UNION ALL의 실행 순서에 의존합니다. 이 추측이 검증될 수 있더라도(YugabyteDB는 오픈 소스임) 이는 선언적이며 절차적이지 않은 SQL 언어를 위반합니다. 언젠가는 최적화가 와서 순서를 바꾸고 버그를 잡을 것입니다.

  • 재귀



    재귀 공통 테이블 표현식(CTE)은 여전히 ​​선언적 SQL인 경우에도 한 수준이 중첩된 수준보다 먼저 실행되어야 하므로 실행 절차 순서를 더 잘 보장합니다. 내 쿼리는 다음과 같습니다.

    with recursive my_cte as (
     select * from customers 
      where id='9f0345c1-ff88-477d-8f87-b6ae3717ba37'
      and yb_is_local_table(tableoid)
     union all 
     (
      select * from customers 
      where id='9f0345c1-ff88-477d-8f87-b6ae3717ba37'
      and not yb_is_local_table(tableoid)
      union all select * from my_cte 
     )
    ) select * from my_cte limit 1;
    


    다음은 내 사용자의 홈인 earth에 연결된 경우의 실행 계획입니다.

    \c - - - 5433
    
    explain (costs off, analyze, summary off)
    with recursive my_cte as (
     select * from customers 
      where id='9f0345c1-ff88-477d-8f87-b6ae3717ba37'
      and yb_is_local_table(tableoid)
     union all 
     (
      select * from customers 
      where id='9f0345c1-ff88-477d-8f87-b6ae3717ba37'
      and not yb_is_local_table(tableoid)
      union all select * from my_cte 
     )
    ) select * from my_cte limit 1;
    
                                                           QUERY PLAN
    ------------------------------------------------------------------------------------------------------------------------
     Limit (actual time=0.650..0.651 rows=1 loops=1)
       CTE my_cte
         ->  Recursive Union (actual time=0.648..0.648 rows=1 loops=1)
               ->  Append (actual time=0.647..0.647 rows=1 loops=1)
                     ->  Index Scan using customers_earth_pkey on customers_earth (actual time=0.646..0.646 rows=1 loops=1)
                           Index Cond: (id = '9f0345c1-ff88-477d-8f87-b6ae3717ba37'::uuid)
                           Filter: yb_is_local_table(tableoid)
               ->  Append (never executed)
                     ->  Append (never executed)
                           ->  Index Scan using customers_earth_pkey on customers_earth customers_earth_1 (never executed)
                                 Index Cond: (id = '9f0345c1-ff88-477d-8f87-b6ae3717ba37'::uuid)
                           ->  Index Scan using customers_mars_pkey on customers_mars (never executed)
                                 Index Cond: (id = '9f0345c1-ff88-477d-8f87-b6ae3717ba37'::uuid)
                           ->  Index Scan using customers_moon_pkey on customers_moon (never executed)
                                 Index Cond: (id = '9f0345c1-ff88-477d-8f87-b6ae3717ba37'::uuid)
                     ->  WorkTable Scan on my_cte my_cte_1 (never executed)
       ->  CTE Scan on my_cte (actual time=0.649..0.649 rows=1 loops=1)
    (17 rows)
    
    

    moon에 연결된 경우에도 동일합니다.

    \c - - - 5434
    
    explain (costs off, analyze, summary off)
    with recursive my_cte as (
     select * from customers 
      where id='9f0345c1-ff88-477d-8f87-b6ae3717ba37'
      and yb_is_local_table(tableoid)
     union all 
     (
      select * from customers 
      where id='9f0345c1-ff88-477d-8f87-b6ae3717ba37'
      and not yb_is_local_table(tableoid)
      union all select * from my_cte 
     )
    ) select * from my_cte limit 1;
    
                                                           QUERY PLAN
    ------------------------------------------------------------------------------------------------------------------------
     Limit (actual time=0.650..0.651 rows=1 loops=1)
       CTE my_cte
         ->  Recursive Union (actual time=0.648..0.648 rows=1 loops=1)
               ->  Append (actual time=0.647..0.647 rows=1 loops=1)
                     ->  Index Scan using customers_earth_pkey on customers_earth (actual time=0.646..0.646 rows=1 loops=1)
                           Index Cond: (id = '9f0345c1-ff88-477d-8f87-b6ae3717ba37'::uuid)
                           Filter: yb_is_local_table(tableoid)
               ->  Append (never executed)
                     ->  Append (never executed)
                           ->  Index Scan using customers_earth_pkey on customers_earth customers_earth_1 (never executed)
                                 Index Cond: (id = '9f0345c1-ff88-477d-8f87-b6ae3717ba37'::uuid)
                           ->  Index Scan using customers_mars_pkey on customers_mars (never executed)
                                 Index Cond: (id = '9f0345c1-ff88-477d-8f87-b6ae3717ba37'::uuid)
                           ->  Index Scan using customers_moon_pkey on customers_moon (never executed)
                                 Index Cond: (id = '9f0345c1-ff88-477d-8f87-b6ae3717ba37'::uuid)
                     ->  WorkTable Scan on my_cte my_cte_1 (never executed)
       ->  CTE Scan on my_cte (actual time=0.649..0.649 rows=1 loops=1)
    (17 rows)
    
    


    이것은 조금 더 복잡한 SQL 문을 대가로 실행 순서에 대한 내 문제를 해결합니다. 여전히 로컬 파티션을 두 번 읽을 수 있다는 문제가 있습니다. 예를 들어 mars에서 사용자를 쿼리하는 경우:

    explain (costs off, analyze, summary off)
    with recursive my_cte as (
     select * from customers 
      where id='841efbb7-4833-4f65-ab07-d557ebc4427a'
      and yb_is_local_table(tableoid)
     union all 
     (
      select * from customers 
      where id='841efbb7-4833-4f65-ab07-d557ebc4427a'
      and not yb_is_local_table(tableoid)
      union all select * from my_cte 
     )
    ) select * from my_cte limit 1;
    
                                                              QUERY PLAN                                                      
    ------------------------------------------------------------------------------------------------------------------------------
     Limit (actual time=2.364..2.365 rows=1 loops=1)
       CTE my_cte
         ->  Recursive Union (actual time=2.362..2.362 rows=1 loops=1)
               ->  Append (actual time=0.871..0.871 rows=0 loops=1)
                     ->  Index Scan using customers_moon_pkey on customers_moon (actual time=0.870..0.870 rows=0 loops=1)
                           Index Cond: (id = '841efbb7-4833-4f65-ab07-d557ebc4427a'::uuid)
                           Filter: yb_is_local_table(tableoid)
               ->  Append (actual time=1.490..1.490 rows=1 loops=1)
                     ->  Append (actual time=1.489..1.489 rows=1 loops=1)
                           ->  Index Scan using customers_earth_pkey on customers_earth (actual time=0.716..0.716 rows=0 loops=1)
                                 Index Cond: (id = '841efbb7-4833-4f65-ab07-d557ebc4427a'::uuid)
                                 Filter: (NOT yb_is_local_table(tableoid))
                           ->  Index Scan using customers_mars_pkey on customers_mars (actual time=0.772..0.772 rows=1 loops=1)
                                 Index Cond: (id = '841efbb7-4833-4f65-ab07-d557ebc4427a'::uuid)
                                 Filter: (NOT yb_is_local_table(tableoid))
                           ->  Index Scan using customers_moon_pkey on customers_moon customers_moon_1 (never executed)
                                 Index Cond: (id = '841efbb7-4833-4f65-ab07-d557ebc4427a'::uuid)
                                 Filter: (NOT yb_is_local_table(tableoid))
                     ->  WorkTable Scan on my_cte my_cte_1 (never executed)
       ->  CTE Scan on my_cte (actual time=2.363..2.363 rows=1 loops=1)
    (20 rows)
    
    


    행이 로컬에서 발견되지 않았으며( customers_moon (actual time=0.870..0.870 rows=0 loops=1) ) 두 번째 반복에서도 발생했습니다.

                     ->  Append (actual time=1.489..1.489 rows=1 loops=1)
                           ->  Index Scan using customers_earth_pkey on customers_earth (actual time=0.716..0.716 rows=0 loops=1)
                                 Index Cond: (id = '841efbb7-4833-4f65-ab07-d557ebc4427a'::uuid)
                                 Filter: (NOT yb_is_local_table(tableoid))
    


    그 이유는 분명히 where not yb_is_local_table() 에 대해 하는 것처럼 where yb_is_local_table() 에 대해 파티션 가지치기를 수행하지 않기 때문입니다. 이것은 일반적으로 지역 간 10ms 또는 100ms인 읽기에 1밀리초를 추가하므로 중요하지 않습니다. 그러나 당신은 문제입니다. 개선을 위해 git 문제를 열 ​​수 있습니다.

    이 블로그 시리즈는 사용자 요구 사항에서 비롯됩니다. 다른 아이디어가 있다면 공유해주세요. YugabyteDB 지리적 분포는 많은 가능성을 제공합니다. 지역 분할을 위한 테이블스페이스에 대해 더 알고 싶다면

    좋은 웹페이지 즐겨찾기