로컬 파티션을 먼저 읽은 다음 로컬에서 찾을 수 없는 경우 전역 읽기
55354 단어 sqlyugabytedbdatabasedistributed
customer_id
를 가지고 있지만 그녀의 나라를 모릅니다. 그러나 그녀의 데이터가 있는 곳에 내가 연결되어 있을 가능성이 높습니다. 유럽 은행의 고객이 아마도 유럽에서 연결하는 것처럼 생각하십시오. 이 경우 대기 시간이 짧은 쿼리를 원합니다. 예를 들어 고객이 여행 중이고 미국에서 쿼리하는 경우 은행 계좌가 유럽에 있음을 알면 대기 시간이 더 길어질 수 있습니다.와 동일한 데이터에서 이 데모를 실행하고 있습니다. 모든 DDL과 DML은 . 로컬 테이블에서 읽기 위해
yb_is_local_table(tableoid)
를 사용했습니다.사용자 지역에 연결
사용자
9f0345c1-ff88-477d-8f87-b6ae3717ba37
는 earth
지역(포트 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
)을 반환하지 않았고 두 번째 분기는 행을 반환할 때까지 분할 후 분할 실행되었습니다.이것은 우리의 목표에 부합합니다. 사용자가 현지에 있을 때는 짧은 대기 시간, 여행 중인 경우에는 더 높은 대기 시간입니다.
그러나 두 가지 문제가 있습니다.
재귀
재귀 공통 테이블 표현식(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 지리적 분포는 많은 가능성을 제공합니다. 지역 분할을 위한 테이블스페이스에 대해 더 알고 싶다면
Reference
이 문제에 관하여(로컬 파티션을 먼저 읽은 다음 로컬에서 찾을 수 없는 경우 전역 읽기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/yugabyte/read-locally-first-then-global-on-not-found-3cdn텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)