По умолчанию все данные из всех опубликованных таблиц реплицируются соответствующим подписчикам. Объем реплицируемых данных может быть ограничен с помощью
фильтр строк. Пользователь может использовать фильтры строк по соображениям функциональности, безопасности или производительности. Если для опубликованной таблицы установлен фильтр строк, строка реплицируется только в том случае, если ее данные удовлетворяют выражению фильтра строк. Это позволяет выполнять частичную репликацию набора таблиц. Фильтр строк определяется для каждой таблицы. Используйте предложение WHERE после имени таблицы для каждой опубликованной таблицы, в которой требуется фильтрация данных. WHERE Предложение должно быть заключено в скобки. См.
CREATE PUBLICATION for details.
Фильтры строк применяются перед публикацией изменений.
Если выражение фильтра строк возвращает значение false или NULL
то строка не реплицируется. Выражение в WHERE предложении
вычисляется с использованием той же роли, которая используется для соединения для репликации (т. е.
роли, указанной в
CONNECTION
предложении CREATE SUBSCRIPTION). Фильтры строк не
влияют на TRUNCATE команду.
Предложение WHERE допускает использование только простых выражений. Оно не может содержать пользовательские функции, операторы, типы и правила сортировки, ссылки на системные столбцы или встроенные функции, не являющиеся постоянными (immutable).
Если публикация включает UPDATE или
DELETE операции, то предложение фильтра строк WHERE
должно содержать только те столбцы, которые входят в идентификатор реплики
(см. REPLICA IDENTITY). Если публикация
включает только INSERT операции, то предложение фильтра строк
WHERE предложение может использовать любой столбец.
При обработке операции UPDATE выражение фильтра строк
вычисляется как для старой, так и для новой строки (т. е. с использованием данных
до и после обновления). Если оба результата вычисления — true,
выполняется репликация UPDATE изменение. Если оба результата вычисления
false, изменение не реплицируется. Если только одна из
старой или новой строк соответствует выражению фильтра строк, то UPDATE
преобразуется в INSERT или DELETE, во избежание
нарушения согласованности данных. Строка на Подписчике должна соответствовать тому, что определено выражением фильтра строк на Издателе.
Если старая строка удовлетворяет выражению фильтра строк (она была отправлена Подписчику), а новая строка — нет, то с точки зрения согласованности данных старая строка должна быть удалена на Подписчике. Следовательно, UPDATE преобразуется в DELETE.
Если старая строка не удовлетворяет выражению фильтра строк (она не была отправлена Подписчику), а новая строка удовлетворяет ему, то с точки зрения согласованности данных новая строка должна быть добавлена на Подписчик. Следовательно, UPDATE преобразуется в INSERT.
Таблица 3.14.1 содержит сводную информацию о примененных преобразованиях.
Таблица 3.14.1. UPDATE Сводка преобразований
| Старая строка | Новая строка | Преобразование |
|---|---|---|
| не соответствует | не соответствует | не реплицировать |
| не соответствует | соответствует | INSERT |
| соответствует | не соответствует | DELETE |
| соответствует | соответствует | UPDATE |
Если публикация содержит секционированную таблицу, параметр публикации
publish_via_partition_root
определяет, какой фильтр строк используется. Если publish_via_partition_root
имеет значение true, то фильтр строк корневой секционированной таблицы
используется. В противном случае, если publish_via_partition_root
имеет значение false (по умолчанию), для каждой секции
используется фильтр строк.
Если подписка требует копирования существующих данных таблицы
и публикация содержит WHERE предложения, на подписчика копируются только те данные, которые удовлетворяют выражениям фильтра строк.
Если подписка включает несколько публикаций, в которых таблица была опубликована с различными WHERE выражения, строки, удовлетворяющие
любому из выражений, будут скопированы. Подробнее см.
Раздел 3.14.4.6 для получения подробных сведений.
Поскольку начальная синхронизация данных не учитывает параметр
«публикация»
при копировании существующих данных таблицы, могут быть скопированы строки, которые не были бы реплицированы с помощью DML. См.
Раздел 3.14.8.1, а также
Раздел 3.14.2.2 для ознакомления с примерами.
Если подписчик использует версию до 15 включительно, при копировании существующих данных фильтры строк не применяются, даже если они определены в публикации. Это связано с тем, что в предыдущих версиях поддерживается только копирование всей таблицы целиком.
Если подписка включает несколько публикаций, в которых одна и та же таблица опубликована с различными фильтрами строк (для одной и той же
«публикация»
операции), эти выражения объединяются оператором OR, так что строки, удовлетворяющие
любому любому из выражений, будут реплицированы. Это означает, что все остальные фильтры строк для той же таблицы становятся избыточными, если:
Одна из публикаций не имеет фильтра строк.
Одна из публикаций была создана с использованием
FOR ALL TABLES.
Данное предложение не допускает использование фильтров строк.
Одна из публикаций была создана с использованием
FOR TABLES IN SCHEMA
и таблица принадлежит к указанной схеме. Данное предложение не допускает использование
фильтров строк.
Создание таблиц для использования в следующих примерах.
test_pub=# CREATE TABLE t1(a int, b int, c text, PRIMARY KEY(a,c)); CREATE TABLE test_pub=# CREATE TABLE t2(d int, e int, f int, PRIMARY KEY(d)); CREATE TABLE test_pub=# CREATE TABLE t3(g int, h int, i int, PRIMARY KEY(g)); CREATE TABLE
Создание нескольких публикаций. Публикация p1 включает одну таблицу
(t1), для которой определен фильтр строк. Публикация
p2 включает две таблицы. Таблица t1 не имеет фильтра
строк, а таблица t2 имеет фильтр строк. Публикация
p3 содержит две таблицы, и для обеих определен фильтр строк.
test_pub=# CREATE PUBLICATION p1 FOR TABLE t1 WHERE (a > 5 AND c = 'Новый Южный Уэльс'); CREATE PUBLICATION test_pub=# CREATE PUBLICATION p2 FOR TABLE t1, t2 WHERE (e = 99); CREATE PUBLICATION test_pub=# CREATE PUBLICATION p3 FOR TABLE t2 WHERE (d = 10), t3 WHERE (g = 10); CREATE PUBLICATION
psql может использоваться для отображения выражений фильтра строк (если они определены) для каждой публикации.
test_pub=# \dRp+
Публикация p1
Владелец | Все таблицы | Вставки | обновления | удаление | команды TRUNCATE | через корневую таблицу
----------+------------+---------+---------+---------+-----------+----------
postgres | f | t | t | t | t | f
Таблицы:
"public.t1" WHERE ((a > 5) AND (c = 'Новый Южный Уэльс'::text))
Публикация p2
Владелец | Все таблицы | Вставки | Обновления | Удаления | Команды TRUNCATE | Через корневую таблицу
----------+------------+---------+---------+---------+-----------+----------
postgres | f | t | t | t | t | f
Таблицы:
"public.t1"
"public.t2" WHERE (e = 99)
Публикация p3
Владелец | Все таблицы | Вставки | Обновления | Удаления | Команды TRUNCATE | Через корневую таблицу
----------+------------+---------+---------+---------+-----------+----------
postgres | f | t | t | t | t | f
Таблицы:
"public.t2" WHERE (d = 10)
"public.t3" WHERE (g = 10)
psql может использоваться для вывода выражений фильтра строк (если они определены) для каждой таблицы. Видно, что таблица t1 входит в состав
двух публикаций, но имеет фильтр строк только в p1.
Видно, что таблица t2 входит в состав двух публикаций и имеет разные фильтры строк в каждой из них.
test_pub=# \d t1
Таблица "public.t1"
Столбец | Тип | Правило сортировки | Допускающий значение NULL | По умолчанию
--------+---------+-----------+----------+---------
a | integer | | не NULL |
b | integer | | |
c | text | | не NULL |
Индексы:
"t1_pkey" PRIMARY KEY, btree (a, c)
Публикации:
"p1" WHERE ((a > 5) AND (c = 'Новый Южный Уэльс'::text))
"p2"
test_pub=# \d t2
Таблица "public.t2"
Столбец | Тип | Правило сортировки | Допускающий значение NULL | По умолчанию
--------+---------+-----------+----------+---------
d | integer | | не NULL |
e | integer | | |
f | integer | | |
Индексы:
"t2_pkey" PRIMARY KEY, btree (d)
Публикации:
"p2" WHERE (e = 99)
"p3" WHERE (d = 10)
test_pub=# \d t3
Таблица "public.t3"
Столбец | Тип | Правило сортировки | Допускающий значение NULL | По умолчанию
--------+---------+-----------+----------+---------
g | integer | | not null |
h | integer | | |
i | integer | | |
Индексы:
"t3_pkey" PRIMARY KEY, btree (g)
Публикации:
"p3" WHERE (g = 10)
На узле-подписчике создается таблица t1 с тем же определением, что и на издателе, а также создание подписки
s1 , подписывающаяся на публикацию p1.
test_sub=# CREATE TABLE t1(a int, b int, c text, PRIMARY KEY(a,c)); CREATE TABLE test_sub=# CREATE SUBSCRIPTION s1 test_sub-# CONNECTION 'host=localhost dbname=test_pub application_name=s1' test_sub-# PUBLICATION p1; CREATE SUBSCRIPTION
Выполняется вставка строк. Только те строки, которые удовлетворяют t1 WHERE
публикации, p1 реплицируются.
test_pub=# INSERT INTO t1 VALUES (2, 102, 'NSW'); INSERT 0 1 test_pub=# INSERT INTO t1 VALUES (3, 103, 'QLD'); INSERT 0 1 test_pub=# INSERT INTO t1 VALUES (4, 104, 'VIC'); INSERT 0 1 test_pub=# INSERT INTO t1 VALUES (5, 105, 'ACT'); INSERT 0 1 test_pub=# INSERT INTO t1 VALUES (6, 106, 'NSW'); INSERT 0 1 test_pub=# INSERT INTO t1 VALUES (7, 107, 'NT'); INSERT 0 1 test_pub=# INSERT INTO t1 VALUES (8, 108, 'QLD'); INSERT 0 1 test_pub=# INSERT INTO t1 VALUES (9, 109, 'NSW'); INSERT 0 1 test_pub=# SELECT * FROM t1; a | b | c ---+-----+----- 2 | 102 | NSW 3 | 103 | QLD 4 | 104 | VIC 5 | 105 | ACT 6 | 106 | NSW 7 | 107 | NT 8 | 108 | QLD 9 | 109 | NSW (8 rows)
test_sub=# SELECT * FROM t1; a | b | c ---+-----+----- 6 | 106 | Новый Южный Уэльс 9 | 109 | Новый Южный Уэльс (2 строки)
Обновление данных, при котором и старые, и новые значения строк удовлетворяют t1 WHERE условию публикации
p1. Функция UPDATE реплицирует
изменение в обычном режиме.
test_pub=# UPDATE t1 SET b = 999 WHERE a = 6; UPDATE 1 test_pub=# SELECT * FROM t1; a | b | c ---+-----+----- 2 | 102 | Новый Южный Уэльс 3 | 103 | Квинсленд 4 | 104 | Виктория 5 | 105 | Действие 7 | 107 | Северная территория 8 | 108 | Квинсленд 9 | 109 | Новый Южный Уэльс 6 | 999 | Новый Южный Уэльс (8 строк)
test_sub=# SELECT * FROM t1; a | b | c ---+-----+----- 9 | 109 | Новый Южный Уэльс 6 | 999 | Новый Южный Уэльс (2 строки)
Обновление данных, при котором старые значения строк не удовлетворяли t1 WHERE условию публикации p1,
однако значения новой строки удовлетворяют этому условию. Это действие UPDATE преобразуется в INSERT и изменение реплицируется.
Проверьте наличие новой строки на стороне подписчика.
test_pub=# UPDATE t1 SET a = 555 WHERE a = 2; UPDATE 1 test_pub=# SELECT * FROM t1; a | b | c -----+-----+----- 3 | 103 | Квинсленд 4 | 104 | Виктория 5 | 105 | Действие 7 | 107 | Северная территория 8 | 108 | Квинсленд 9 | 109 | Новый Южный Уэльс 6 | 999 | Новый Южный Уэльс 555 | 102 | Новый Южный Уэльс (8 rows)
test_sub=# SELECT * FROM t1; a | b | c -----+-----+----- 9 | 109 | Новый Южный Уэльс 6 | 999 | Новый Южный Уэльс 555 | 102 | Новый Южный Уэльс (3 rows)
Обновление данных, в которых значения исходной строки соответствовали
условию t1 WHERE условию публикации p1,
а значения новой строки — нет. Данное действие UPDATE преобразуется
в DELETE и изменение реплицируется.
Следует отметить, что строка удаляется на стороне подписчика.
test_pub=# UPDATE t1 SET c = 'VIC' WHERE a = 9; UPDATE 1 test_pub=# SELECT * FROM t1; a | b | c -----+-----+----- 3 | 103 | QLD 4 | 104 | VIC 5 | 105 | ACT 7 | 107 | NT 8 | 108 | QLD 6 | 999 | NSW 555 | 102 | NSW 9 | 109 | VIC (8 rows)
test_sub=# SELECT * FROM t1; a | b | c -----+-----+----- 6 | 999 | NSW 555 | 102 | NSW (2 rows)
Следующие примеры демонстрируют, как параметр публикации
publish_via_partition_root
определяет, какой фильтр строк (родительской или дочерней таблицы) будет использоваться
в случае секционированных таблиц.
Создайте секционированную таблицу на издателе.
test_pub=# CREATE TABLE parent(a int PRIMARY KEY) PARTITION BY RANGE(a); CREATE TABLE test_pub=# CREATE TABLE child PARTITION OF parent DEFAULT; CREATE TABLE
Создайте такие же таблицы на подписчике.
test_sub=# CREATE TABLE parent(a int PRIMARY KEY) PARTITION BY RANGE(a); CREATE TABLE test_sub=# CREATE TABLE child PARTITION OF parent DEFAULT; CREATE TABLE
Создайте публикацию p4, а затем подпишитесь на нее. Параметр публикации publish_via_partition_root установлен
в значение true. Фильтры строк определены как для секционированной таблицы
(родительская таблица), так и для секции (дочерняя таблица).
test_pub=# CREATE PUBLICATION p4 FOR TABLE parent WHERE (a < 5), child WHERE (a >= 5) test_pub-# WITH (publish_via_partition_root=true); CREATE PUBLICATION
test_sub=# CREATE SUBSCRIPTION s4 test_sub-# CONNECTION 'host=localhost dbname=test_pub application_name=s4' test_sub-# PUBLICATION p4; CREATE SUBSCRIPTION
Вставьте несколько значений напрямую в родительская таблица и
дочерняя таблица таблицы. Репликация выполняется с использованием фильтра строк
родительская таблица (поскольку publish_via_partition_root
истинно).
test_pub=# INSERT INTO parent VALUES (2), (4), (6); INSERT 0 3 test_pub=# INSERT INTO child VALUES (3), (5), (7); INSERT 0 3 test_pub=# SELECT * FROM parent ORDER BY a; a --- 2 3 4 5 6 7 (6 rows)
test_sub=# SELECT * FROM parent ORDER BY a; a --- 2 3 4 (3 rows)
Повторите тот же тест, но с другим значением для publish_via_partition_root.
Параметр публикации publish_via_partition_root устанавливается в значение false. Фильтр строк определен для секции (дочерняя таблица).
test_pub=# DROP PUBLICATION p4; DROP PUBLICATION test_pub=# CREATE PUBLICATION p4 FOR TABLE parent, child WHERE (a >= 5) test_pub-# WITH (publish_via_partition_root=false); CREATE PUBLICATION
test_sub=# ALTER SUBSCRIPTION s4 REFRESH PUBLICATION; ALTER SUBSCRIPTION
Выполните операции вставки на издателе аналогично предыдущим действиям. Репликация осуществляется с использованием фильтра строк дочерняя таблица (поскольку
publish_via_partition_root имеет значение false).
test_pub=# TRUNCATE parent; TRUNCATE TABLE test_pub=# INSERT INTO parent VALUES (2), (4), (6); INSERT 0 3 test_pub=# INSERT INTO child VALUES (3), (5), (7); INSERT 0 3 test_pub=# SELECT * FROM parent ORDER BY a; a --- 2 3 4 5 6 7 (6 rows)
test_sub=# SELECT * FROM child ORDER BY a; a --- 5 6 7 (3 rows)