DBA: Π³Ρ€Π°ΠΌΠΎΡ‚Π½ΠΎ ΠΎΡ€Π³Π°Π½ΠΈΠ·ΠΎΠ²Ρ‹Π²Π°Π΅ΠΌ синхронизации ΠΈ ΠΈΠΌΠΏΠΎΡ€Ρ‚Ρ‹

ΠŸΡ€ΠΈ слоТной ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅ Π±ΠΎΠ»ΡŒΡˆΠΈΡ… Π½Π°Π±ΠΎΡ€ΠΎΠ² Π΄Π°Π½Π½Ρ‹Ρ… (Ρ€Π°Π·Π½Ρ‹Π΅ ETL-процСссы: ΠΈΠΌΠΏΠΎΡ€Ρ‚Ρ‹, ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚Π°Ρ†ΠΈΠΈ ΠΈ синхронизации с внСшним источником) часто Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ Β«Π·Π°ΠΏΠΎΠΌΠ½ΠΈΡ‚ΡŒΒ», ΠΈ сразу быстро ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ объСмноС.

Виповая Π·Π°Π΄Π°Ρ‡Π° ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΎΠ³ΠΎ Ρ€ΠΎΠ΄Π° Π·Π²ΡƒΡ‡ΠΈΡ‚ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ Ρ‚Π°ΠΊ: Β«Π’ΠΎΡ‚ Ρ‚ΡƒΡ‚ бухгалтСрия Π²Ρ‹Π³Ρ€ΡƒΠ·ΠΈΠ»Π° ΠΈΠ· ΠΊΠ»ΠΈΠ΅Π½Ρ‚-Π±Π°Π½ΠΊΠ° послСдниС ΠΏΠΎΡΡ‚ΡƒΠΏΠΈΠ²ΡˆΠΈΠ΅ ΠΎΠΏΠ»Π°Ρ‚Ρ‹, Π½Π°Π΄ΠΎ ΠΈΡ… Π±Ρ‹ΡΡ‚Ρ€Π΅Π½ΡŒΠΊΠΎ Π²ΠΊΠ°Ρ‡Π°Ρ‚ΡŒ Π½Π° сайт ΠΈ ΠΏΡ€ΠΈΠ²ΡΠ·Π°Ρ‚ΡŒ ΠΊ счСтам»

Но ΠΊΠΎΠ³Π΄Π° объСм этого Β«Ρ‡Π΅Π³ΠΎ-Ρ‚ΠΎΒ» Π½Π°Ρ‡ΠΈΠ½Π°Π΅Ρ‚ ΠΈΠ·ΠΌΠ΅Ρ€ΡΡ‚ΡŒΡΡ сотнями ΠΌΠ΅Π³Π°Π±Π°ΠΉΡ‚, Π° сСрвис ΠΏΡ€ΠΈ этом Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ°Ρ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с Π±Π°Π·ΠΎΠΉ Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ 24×7, Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ мноТСство side-эффСктов, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΠΎΡ€Ρ‚ΠΈΡ‚ΡŒ Π²Π°ΠΌ Тизнь.
DBA: Π³Ρ€Π°ΠΌΠΎΡ‚Π½ΠΎ ΠΎΡ€Π³Π°Π½ΠΈΠ·ΠΎΠ²Ρ‹Π²Π°Π΅ΠΌ синхронизации ΠΈ ΠΈΠΌΠΏΠΎΡ€Ρ‚Ρ‹
Π§Ρ‚ΠΎΠ±Ρ‹ ΡΠΏΡ€Π°Π²ΠΈΡ‚ΡŒΡΡ с Π½ΠΈΠΌΠΈ Π² PostgreSQL (Π΄Π° ΠΈ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² Π½Π΅ΠΌ), ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ возмоТности для ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ позволят ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ всС быстрСС ΠΈ с мСньшим расходом рСсурсов.

1. ΠšΡƒΠ΄Π° Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ?

Π‘Π½Π°Ρ‡Π°Π»Π° Π΄Π°Π²Π°ΠΉΡ‚Π΅ опрСдСлимся, ΠΊΡƒΠ΄Π° ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π·Π°Π»ΠΈΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ Β«ΠΎΡ‚ΠΏΡ€ΠΎΡ†Π΅ΡΡΠΈΡ‚ΡŒΒ».

1.1. Π’Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ (TEMPORARY TABLE)

Π’ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ΅, для PostgreSQL Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ β€” это Ρ‚Π°ΠΊΠΈΠ΅ ΠΆΠ΅ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹, ΠΊΠ°ΠΊ ΠΈ Π»ΡŽΠ±Ρ‹Π΅ Π΄Ρ€ΡƒΠ³ΠΈΠ΅. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ Π½Π΅Π²Π΅Ρ€Π½Ρ‹ суСвСрия Ρ‚ΠΈΠΏΠ° Β«Ρ‚Π°ΠΌ всС хранится Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² памяти, Π° ΠΎΠ½Π° ΠΌΠΎΠΆΠ΅Ρ‚ ΠΊΠΎΠ½Ρ‡ΠΈΡ‚ΡŒΡΡΒ». Но Π΅ΡΡ‚ΡŒ ΠΈ нСсколько сущСствСнных ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠΉ.

Π‘Π²ΠΎΠΉ «нСймспСйс» для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ ΠΊ Π‘Π”

Если Π΄Π²Π° ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ ΠΏΠΎΠΏΡ‹Ρ‚Π°ΡŽΡ‚ΡΡ ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ CREATE TABLE x, Ρ‚ΠΎ ΠΊΡ‚ΠΎ-Ρ‚ΠΎ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ ΠΎΡˆΠΈΠ±ΠΊΡƒ Π½Π΅ΡƒΠ½ΠΈΠΊΠ°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Π‘Π”.

А Π²ΠΎΡ‚ Ссли ΠΎΠ±Π° ΠΏΠΎΠΏΡ‹Ρ‚Π°ΡŽΡ‚ΡΡ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ CREATE TEMPORARY TABLE x, Ρ‚ΠΎ ΠΎΠ±Π° Π½ΠΎΡ€ΠΌΠ°Π»ΡŒΠ½ΠΎ это ΡΠ΄Π΅Π»Π°ΡŽΡ‚, ΠΈ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ свой экзСмпляр Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹. И Π½ΠΈΡ‡Π΅Π³ΠΎ ΠΎΠ±Ρ‰Π΅Π³ΠΎ ΠΌΠ΅ΠΆΠ΄Ρƒ Π½ΠΈΠΌΠΈ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚.

Β«Π‘Π°ΠΌΠΎΡƒΠ½ΠΈΡ‡Ρ‚ΠΎΠΆΠ΅Π½ΠΈΠ΅Β» ΠΏΡ€ΠΈ disconnect

ΠŸΡ€ΠΈ Π·Π°ΠΊΡ€Ρ‹Ρ‚ΠΈΠΈ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ всС Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ автоматичСски ΡƒΠ΄Π°Π»ΡΡŽΡ‚ΡΡ, поэтому Β«Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽΒ» Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒ DROP TABLE x смысла Π½Π΅Ρ‚ Π½ΠΈΠΊΠ°ΠΊΠΎΠ³ΠΎ, кромС…

Если Π²Ρ‹ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚Π΅ Ρ‡Π΅Ρ€Π΅Π· pgbouncer Π² transaction mode, Ρ‚ΠΎ Π±Π°Π·Π°-Ρ‚ΠΎ ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ°Π΅Ρ‚ ΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ это соСдинСниС всС Π΅Ρ‰Π΅ Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎ, ΠΈ Π² Π½Π΅ΠΌ-Ρ‚ΠΎ эта врСмСнная Ρ‚Π°Π±Π»ΠΈΡ†Π° ΠΏΠΎ-ΠΏΡ€Π΅ΠΆΠ½Π΅ΠΌΡƒ сущСствуСт.

ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ ΠΏΠΎΠΏΡ‹Ρ‚ΠΊΠ° ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π΅Π΅ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎ, ΡƒΠΆΠ΅ ΠΈΠ· Π΄Ρ€ΡƒΠ³ΠΎΠ³ΠΎ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ ΠΊ pgbouncer, ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Ρ‚ ΠΊ ошибкС. Но это ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ±ΠΎΠΉΡ‚ΠΈ, воспользовавшись CREATE TEMPORARY TABLE IF NOT EXISTS x.

ΠŸΡ€Π°Π²Π΄Π°, Π»ΡƒΡ‡ΡˆΠ΅ Ρ‚Π°ΠΊ всС-Ρ‚Π°ΠΊΠΈ Π½Π΅ Π΄Π΅Π»Π°Ρ‚ΡŒ, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ Π·Π°Ρ‚Π΅ΠΌ ΠΌΠΎΠΆΠ½ΠΎ Β«Π²Π½Π΅Π·Π°ΠΏΠ½ΠΎΒ» ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠΈΡ‚ΡŒ Ρ‚Π°ΠΌ, ΠΎΡΡ‚Π°Π²ΡˆΠΈΠ΅ΡΡ ΠΎΡ‚ Β«ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅Π³ΠΎ Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π°Β» Π΄Π°Π½Π½Ρ‹Π΅. ВмСсто этого Π³ΠΎΡ€Π°Π·Π΄ΠΎ Π»ΡƒΡ‡ΡˆΠ΅ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ-Ρ‚Π°ΠΊΠΈ ΠΌΠ°Π½ΡƒΠ°Π», ΠΈ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΈ создании Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π΅ΡΡ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π΄ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ ON COMMIT DROP β€” Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ ΠΏΡ€ΠΈ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠΈ Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΈ Ρ‚Π°Π±Π»ΠΈΡ†Π° Π±ΡƒΠ΄Π΅Ρ‚ автоматичСски ΡƒΠ΄Π°Π»Π΅Π½Π°.

НС-рСпликация

Π’ силу принадлСТности Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠΌΡƒ соСдинСнию, Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π½Π΅ Ρ€Π΅ΠΏΠ»ΠΈΡ†ΠΈΡ€ΡƒΡŽΡ‚ΡΡ. Π—Π°Ρ‚ΠΎ это избавляСт ΠΎΡ‚ нСобходимости Π΄Π²ΠΎΠΉΠ½ΠΎΠΉ записи Π΄Π°Π½Π½Ρ‹Ρ… Π² heap + WAL, поэтому INSERT/UPDATE/DELETE Π² Π½Π΅Π΅ сущСствСнно быстрСС.

Но ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ врСмСнная β€” это всС-Ρ‚Π°ΠΊΠΈ Β«ΠΏΠΎΡ‡Ρ‚ΠΈ обычная» Ρ‚Π°Π±Π»ΠΈΡ†Π°, Ρ‚ΠΎ ΠΈ Π½Π° Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ΅ Π΅Π΅ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ нСльзя Ρ‚ΠΎΠΆΠ΅. По ΠΊΡ€Π°ΠΉΠ½Π΅ΠΉ ΠΌΠ΅Ρ€Π΅, ΠΏΠΎΠΊΠ°, хотя ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ ΠΏΠ°Ρ‚Ρ‡ ΡƒΠΆΠ΅ Π΄Π°Π²Π½ΠΎ Ρ…ΠΎΠ΄ΠΈΡ‚.

1.2. НСТурналируСмыС Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ (UNLOGGED TABLE)

Но Ρ‡Ρ‚ΠΎ Π΄Π΅Π»Π°Ρ‚ΡŒ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Ссли Ρƒ вас Π΅ΡΡ‚ΡŒ ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ Π³Ρ€ΠΎΠΌΠΎΠ·Π΄ΠΊΠΈΠΉ ETL-процСсс, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π½Π΅ удаСтся Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π² Ρ€Π°ΠΌΠΊΠ°Ρ… ΠΎΠ΄Π½ΠΎΠΉ Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΈ, Π° Ρƒ вас Ρ‚Π°ΠΊΠΈ pgbouncer Π² transaction mode?..

Или ΠΏΠΎΡ‚ΠΎΠΊ Π΄Π°Π½Π½Ρ‹Ρ… Π½Π°ΡΡ‚ΠΎΠ»ΡŒΠΊΠΎ Π²Π΅Π»ΠΈΠΊ, Ρ‡Ρ‚ΠΎ нСдостаточно пропускной способности ΠΎΠ΄Π½ΠΎΠ³ΠΎ соСдинСния с Π‘Π” (Ρ‡ΠΈΡ‚Π°ΠΉ, ΠΎΠ΄Π½ΠΎΠ³ΠΎ процСсса Π½Π° CPU)?..

Или Ρ‡Π°ΡΡ‚ΡŒ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ ΠΈΠ΄ΡƒΡ‚ асинхронно Π² Ρ€Π°Π·Π½Ρ‹Ρ… ΠΊΠΎΠ½Π½Π΅ΠΊΡ‚Π°Ρ…?..

Π’ΡƒΡ‚ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄ΠΈΠ½ β€” Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ Π½Π΅-Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ. ΠšΠ°Π»Π°ΠΌΠ±ΡƒΡ€, Π°Π³Π°. Π’ΠΎ Π΅ΡΡ‚ΡŒ:

  • создал «свои» Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ с максимально-случайными ΠΈΠΌΠ΅Π½Π°ΠΌΠΈ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½ΠΈ с ΠΊΠ΅ΠΌ Π½Π΅ ΠΏΠ΅Ρ€Π΅ΡΠ΅Ρ‡ΡŒΡΡ
  • Extract: Π·Π°Π»ΠΈΠ» Π² Π½ΠΈΡ… Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠ· внСшнСго источника
  • Transform: ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π», Π·Π°ΠΏΠΎΠ»Π½ΠΈΠ» ΠΊΠ»ΡŽΡ‡Π΅Π²Ρ‹Π΅ ΡΠ²ΡΠ·Ρ‹Π²Π°ΡŽΡ‰ΠΈΠ΅ поля
  • Load: ΠΏΠ΅Ρ€Π΅Π»ΠΈΠ» Π³ΠΎΡ‚ΠΎΠ²Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ Π² Ρ†Π΅Π»Π΅Π²Ρ‹Π΅ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹
  • ΡƒΠ΄Π°Π»ΠΈΠ» «свои» Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹

А Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ β€” Π»ΠΎΠΆΠΊΠ° дСгтя. По сути, вся запись Π² PostgreSQL происходит Π΄Π²Π°ΠΆΠ΄Ρ‹ β€” сначала Π² WAL, ΠΏΠΎΡ‚ΠΎΠΌ ΡƒΠΆΠ΅ Π² Ρ‚Π΅Π»Π° Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹/индСксов. ВсС это сдСлано для ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ ACID ΠΈ ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎΠΉ видимости Π΄Π°Π½Π½Ρ‹Ρ… ΠΌΠ΅ΠΆΠ΄Ρƒ COMMIT‘Π½ΡƒΡ‚Ρ‹ΠΌΠΈ ΠΈ ROLLBACK‘Π½ΡƒΡ‚Ρ‹ΠΌΠΈ транзакциями.

Но Π½Π°ΠΌ-Ρ‚ΠΎ этого Π½Π΅ Π½ΡƒΠΆΠ½ΠΎ! Π£ нас вСсь процСсс ΠΈΠ»ΠΈ Ρ†Π΅Π»ΠΈΠΊΠΎΠΌ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΏΡ€ΠΎΡˆΠ΅Π», ΠΈΠ»ΠΈ Π½Π΅Ρ‚. НСваТно, сколько Π² Π½Π΅ΠΌ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΎΡ‡Π½Ρ‹Ρ… Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΉ β€” Π½Π°ΠΌ Π½Π΅ интСрСсно Β«ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ°Ρ‚ΡŒ процСсс с сСрСдины», особСнно ΠΊΠΎΠ³Π΄Π° нСпонятно, Π³Π΄Π΅ ΠΎΠ½Π° Π±Ρ‹Π»Π°.

Для этого Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ PostgreSQL Π΅Ρ‰Π΅ Π² вСрсии 9.1 Π²Π½Π΅Π΄Ρ€ΠΈΠ»ΠΈ Ρ‚Π°ΠΊΡƒΡŽ ΡˆΡ‚ΡƒΠΊΡƒ ΠΊΠ°ΠΊ Π½Π΅ΠΆΡƒΡ€Π½Π°Π»ΠΈΡ€ΡƒΠ΅ΠΌΡ‹Π΅ (UNLOGGED) Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹:

Π‘ этим ΡƒΠΊΠ°Π·Π°Π½ΠΈΠ΅ΠΌ Ρ‚Π°Π±Π»ΠΈΡ†Π° создаётся ΠΊΠ°ΠΊ нСТурналируСмая. Π”Π°Π½Π½Ρ‹Π΅, записываСмыС Π² Π½Π΅ΠΆΡƒΡ€Π½Π°Π»ΠΈΡ€ΡƒΠ΅ΠΌΡ‹Π΅ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹, Π½Π΅ проходят Ρ‡Π΅Ρ€Π΅Π· ΠΆΡƒΡ€Π½Π°Π» прСдзаписи (см. Π“Π»Π°Π²Ρƒ 29), Π² Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ Ρ‡Π΅Π³ΠΎ Ρ‚Π°ΠΊΠΈΠ΅ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ Π³ΠΎΡ€Π°Π·Π΄ΠΎ быстрСС ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹Ρ…. Однако, ΠΎΠ½ΠΈ Π½Π΅ Π·Π°Ρ‰ΠΈΡ‰Π΅Π½Ρ‹ ΠΎΡ‚ сбоя; ΠΏΡ€ΠΈ сбоС ΠΈΠ»ΠΈ Π°Π²Π°Ρ€ΠΈΠΉΠ½ΠΎΠΌ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΈ сСрвСра нСТурналируСмая Ρ‚Π°Π±Π»ΠΈΡ†Π° автоматичСски усСкаСтся. ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, содСрТимоС Π½Π΅ΠΆΡƒΡ€Π½Π°Π»ΠΈΡ€ΡƒΠ΅ΠΌΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π½Π΅ рСплицируСтся Π½Π° Π²Π΅Π΄ΠΎΠΌΡ‹Π΅ сСрвСры. Π›ΡŽΠ±Ρ‹Π΅ индСксы, создаваСмыС для Π½Π΅ΠΆΡƒΡ€Π½Π°Π»ΠΈΡ€ΡƒΠ΅ΠΌΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹, автоматичСски становятся Π½Π΅ΠΆΡƒΡ€Π½Π°Π»ΠΈΡ€ΡƒΠ΅ΠΌΡ‹ΠΌΠΈ.

ΠšΠΎΡ€ΠΎΡ‡Π΅, Π±ΡƒΠ΄Π΅Ρ‚ сильно быстрСС, Π½ΠΎ Ссли сСрвСр Π‘Π” Β«ΡƒΠΏΠ°Π΄Π΅Ρ‚Β» β€” Π±ΡƒΠ΄Π΅Ρ‚ нСприятно. Но часто Π»ΠΈ это происходит, ΠΈ ΡƒΠΌΠ΅Π΅Ρ‚ Π»ΠΈ ваш ETL-процСсс это ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎ Π΄ΠΎΡ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ «с сСрСдины» послС «оТивлСния» Π‘Π”?..

Если Ρ‚Π°ΠΊΠΈ Π½Π΅Ρ‚, ΠΈ кСйс Π²Ρ‹ΡˆΠ΅ ΠΏΠΎΡ…ΠΎΠΆ Π½Π° ваш β€” ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ UNLOGGED, Π½ΠΎ Π½ΠΈΠΊΠΎΠ³Π΄Π° Π½Π΅ Π²ΠΊΠ»ΡŽΡ‡Π°ΠΉΡ‚Π΅ этот Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚ Π½Π° Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Ρ… Ρ‚Π°Π±Π»ΠΈΡ†Π°Ρ…, Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠ· ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Π²Π°ΠΌ Π΄ΠΎΡ€ΠΎΠ³ΠΈ.

1.3. ON COMMIT { DELETE ROWS | DROP }

Π­Ρ‚Π° конструкция позволяСт ΠΏΡ€ΠΈ создании Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π·Π°Π΄Π°Ρ‚ΡŒ автоматичСскоС ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ ΠΏΡ€ΠΈ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠΈ Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΈ.

ΠŸΡ€ΠΎ ON COMMIT DROP я ΡƒΠΆΠ΅ написал Π²Ρ‹ΡˆΠ΅, ΠΎΠ½ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ DROP TABLE, Π° Π²ΠΎΡ‚ с ON COMMIT DELETE ROWS ситуация интСрСснСС β€” Ρ‚ΡƒΡ‚ гСнСрируСтся TRUNCATE TABLE.

ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ вся инфраструктура хранСния мСтаописания Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Ρ€ΠΎΠ²Π½ΠΎ такая ΠΆΠ΅, ΠΊΠ°ΠΊ ΠΈ Ρƒ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠΉ, Ρ‚ΠΎ постоянноС созданиС-ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠ΅ Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… Ρ‚Π°Π±Π»ΠΈΡ† ΠΏΡ€ΠΈΠ²ΠΎΠ΄ΠΈΡ‚ ΠΊ ΡΠΈΠ»ΡŒΠ½ΠΎΠΌΡƒ Β«Ρ€Π°Π·Π±ΡƒΡ…Π°Π½ΠΈΡŽΒ» систСмных Ρ‚Π°Π±Π»ΠΈΡ† pg_class, pg_attribute, pg_attrdef, pg_depend,…

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²ΡŒΡ‚Π΅, Ρ‡Ρ‚ΠΎ Ρƒ вас Π΅ΡΡ‚ΡŒ Π²ΠΎΡ€ΠΊΠ΅Ρ€ Π½Π° прямом соСдинСнии с Π‘Π”, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΊΠ°ΠΆΠ΄ΡƒΡŽ сСкунду ΠΎΡ‚ΠΊΡ€Ρ‹Π²Π°Π΅Ρ‚ Π½ΠΎΠ²ΡƒΡŽ Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΡŽ, создаСт, наполняСт, ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ ΠΈ удаляСт Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ таблицу… ΠœΡƒΡΠΎΡ€Π° Π² систСмных Ρ‚Π°Π±Π»ΠΈΡ†Π°Ρ… накопится Π² ΠΈΠ·Π±Ρ‹Ρ‚ΠΊΠ΅, Π° это лишниС Ρ‚ΠΎΡ€ΠΌΠΎΠ·Π° ΠΏΡ€ΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ.

Π’ ΠΎΠ±Ρ‰Π΅ΠΌ, Π½Π΅ Π½Π°Π΄ΠΎ Ρ‚Π°ΠΊ! Π’ этом случаС Π³ΠΎΡ€Π°Π·Π΄ΠΎ эффСктивнСС CREATE TEMPORARY TABLE x ... ON COMMIT DELETE ROWS вынСсти Π·Π° Ρ†ΠΈΠΊΠ» Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΉ β€” Ρ‚ΠΎΠ³Π΄Π° ΠΊ Π½Π°Ρ‡Π°Π»Ρƒ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ Π½ΠΎΠ²ΠΎΠΉ Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΈ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ ΡƒΠΆΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ (экономим Π²Ρ‹Π·ΠΎΠ² CREATE), Π½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ пустой, благодаря TRUNCATE (Π΅Π³ΠΎ Π²Ρ‹Π·ΠΎΠ² ΠΌΡ‹ Ρ‚ΠΎΠΆΠ΅ сэкономили) ΠΏΡ€ΠΈ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠΈ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΉ Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΈ.

1.4. LIKE… INCLUDING …

Π― упомянул Π² Π½Π°Ρ‡Π°Π»Π΅, Ρ‡Ρ‚ΠΎ ΠΎΠ΄ΠΈΠ½ ΠΈΠ· Ρ‚ΠΈΠΏΠΈΡ‡Π½Ρ‹Ρ… use case для Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… Ρ‚Π°Π±Π»ΠΈΡ† β€” это Ρ€Π°Π·Π½ΠΎΠ³ΠΎ Ρ€ΠΎΠ΄Π° ΠΈΠΌΠΏΠΎΡ€Ρ‚Ρ‹ β€” ΠΈ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ устало копипастит список ΠΏΠΎΠ»Π΅ΠΉ Ρ†Π΅Π»Π΅Π²ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π² объявлСниС своСй врСмСнной…

Но лСнь β€” Π΄Π²ΠΈΠ³Π°Ρ‚Π΅Π»ΡŒ прогрСсса! ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ Β«ΠΏΠΎ ΠΎΠ±Ρ€Π°Π·Ρ†ΡƒΒ» ΠΌΠΎΠΆΠ½ΠΎ Π³ΠΎΡ€Π°Π·Π΄ΠΎ ΠΏΡ€ΠΎΡ‰Π΅:

CREATE TEMPORARY TABLE import_table(
  LIKE target_table
);

ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Π½Π°Π³Π΅Π½Π΅Ρ€ΠΈΡ‚ΡŒ ΠΏΠΎΡ‚ΠΎΠΌ Π² эту Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ ΠΌΠΎΠΆΠ½ΠΎ вСсьма ΠΌΠ½ΠΎΠ³ΠΎ Π΄Π°Π½Π½Ρ‹Ρ…, Ρ‚ΠΎ поиски ΠΏΠΎ Π½Π΅ΠΉ станут Π½ΠΈ Ρ€Π°Π·Ρƒ Π½Π΅ быстрыми. Но ΠΏΡ€ΠΎΡ‚ΠΈΠ² этого Π΅ΡΡ‚ΡŒ Ρ‚Ρ€Π°Π΄ΠΈΡ†ΠΈΠΎΠ½Π½ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ β€” индСксы! И, Π΄Π°, Ρƒ Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Ρ‚ΠΎΠΆΠ΅ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ индСксы.

ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ, Π·Π°Ρ‡Π°ΡΡ‚ΡƒΡŽ, Π½ΡƒΠΆΠ½Ρ‹Π΅ индСксы ΡΠΎΠ²ΠΏΠ°Π΄Π°ΡŽΡ‚ с индСксами Ρ†Π΅Π»Π΅Π²ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹, Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ просто Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ LIKE target_table INCLUDING INDEXES.

Если Π²Π°ΠΌ Π½ΡƒΠΆΠ½Ρ‹ Π΅Ρ‰Π΅ ΠΈ DEFAULT-значСния (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, для заполнСния Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ ΠΏΠ΅Ρ€Π²ΠΈΡ‡Π½ΠΎΠ³ΠΎ ΠΊΠ»ΡŽΡ‡Π°), ΠΌΠΎΠΆΠ½ΠΎ Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ LIKE target_table INCLUDING DEFAULTS. Ну ΠΈΠ»ΠΈ просто β€” LIKE target_table INCLUDING ALL β€” скопируСт Π΄Π΅Ρ„ΠΎΠ»Ρ‚Ρ‹, индСксы, констрСйнты,…

Но Ρ‚ΡƒΡ‚ ΡƒΠΆΠ΅ Π½Π°Π΄ΠΎ ΠΏΠΎΠ½ΠΈΠΌΠ°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ Ссли Π²Ρ‹ создавали ΠΈΠΌΠΏΠΎΡ€Ρ‚-Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ сразу с индСксами, Ρ‚ΠΎ Π·Π°Π»ΠΈΠ²Π°Ρ‚ΡŒΡΡ Π΄Π°Π½Π½Ρ‹Π΅ Π±ΡƒΠ΄ΡƒΡ‚ дольшС, Ρ‡Π΅ΠΌ Ссли сначала всС Π·Π°Π»ΠΈΡ‚ΡŒ, Π° ΡƒΠΆΠ΅ ΠΏΠΎΡ‚ΠΎΠΌ Π½Π°ΠΊΠ°Ρ‚ΠΈΡ‚ΡŒ индСксы β€” посмотритС Π² качСствС ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°, ΠΊΠ°ΠΊ это Π΄Π΅Π»Π°Π΅Ρ‚ pg_dump.

Π’ ΠΎΠ±Ρ‰Π΅ΠΌ, RTFM!

2. Как ΠΏΠΈΡΠ°Ρ‚ΡŒ?

Π‘ΠΊΠ°ΠΆΡƒ просто β€” ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ COPY-ΠΏΠΎΡ‚ΠΎΠΊ вмСсто Β«ΠΏΠ°Ρ‡ΠΊΠΈΒ» INSERT, ускорСниС Π² Ρ€Π°Π·Ρ‹. МоТно Π΄Π°ΠΆΠ΅ прямо ΠΈΠ· ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ сформированного Ρ„Π°ΠΉΠ»Π°.

3. Как ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ?

Π˜Ρ‚Π°ΠΊ, ΠΏΡƒΡΡ‚ΡŒ наша вводная выглядит ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ Ρ‚Π°ΠΊ:

  • Ρƒ вас Π² Π±Π°Π·Π΅ хранится Ρ‚Π°Π±Π»ΠΈΡ‡ΠΊΠ° с клиСнтскими Π΄Π°Π½Π½Ρ‹ΠΌΠΈ Π½Π° 1M записСй
  • ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ дСнь ΠΊΠ»ΠΈΠ΅Π½Ρ‚ присылаСт Π²Π°ΠΌ Π½ΠΎΠ²Ρ‹ΠΉ ΠΏΠΎΠ»Π½Ρ‹ΠΉ Β«ΠΎΠ±Ρ€Π°Π·Β»
  • ΠΏΠΎ ΠΎΠΏΡ‹Ρ‚Ρƒ Π²Ρ‹ Π·Π½Π°Π΅Ρ‚Π΅, Ρ‡Ρ‚ΠΎ ΠΎΡ‚ Ρ€Π°Π·Π° ΠΊ Ρ€Π°Π·Ρƒ измСняСтся Π½Π΅ Π±ΠΎΠ»Π΅Π΅ 10K записСй

ΠšΠ»Π°ΡΡΠΈΡ‡Π΅ΡΠΊΠΈΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠΌ ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΎΠΉ ситуации являСтся Π±Π°Π·Π° ΠšΠ›ΠΠ”Π  β€” всСго адрСсов ΠΌΠ½ΠΎΠ³ΠΎ, Π½ΠΎ Π² ΠΊΠ°ΠΆΠ΄ΠΎΠΉ нСдСльной Π²Ρ‹Π³Ρ€ΡƒΠ·ΠΊΠ΅ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ (ΠΏΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½ΠΈΠΉ насСлСнных ΠΏΡƒΠ½ΠΊΡ‚ΠΎΠ², объСдинСний ΡƒΠ»ΠΈΡ†, появлСний Π½ΠΎΠ²Ρ‹Ρ… Π΄ΠΎΠΌΠΎΠ²) совсСм Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ Π΄Π°ΠΆΠ΅ Π² ΠΌΠ°ΡΡˆΡ‚Π°Π±Π΅ всСй страны.

3.1. Алгоритм ΠΏΠΎΠ»Π½ΠΎΠΉ синхронизации

Для простоты допустим, Ρ‡Ρ‚ΠΎ Π²Π°ΠΌ Π΄Π°ΠΆΠ΅ Ρ€Π΅ΡΡ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ Π½Π΅ Π½ΡƒΠΆΠ½ΠΎ β€” просто привСсти Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ Π² Π½ΡƒΠΆΠ½Ρ‹ΠΉ Π²ΠΈΠ΄, Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ:

  • ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ всС, Ρ‡Π΅Π³ΠΎ ΡƒΠΆΠ΅ Π½Π΅Ρ‚
  • ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ всС, Ρ‡Ρ‚ΠΎ ΡƒΠΆΠ΅ Π±Ρ‹Π»ΠΎ, ΠΈ Π½Π°Π΄ΠΎ ΠΎΠ±Π½ΠΎΠ²Π»ΡΡ‚ΡŒ
  • Π²ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ всС, Ρ‡Π΅Π³ΠΎ Π΅Ρ‰Π΅ Π½Π΅ Π±Ρ‹Π»ΠΎ

ΠŸΠΎΡ‡Π΅ΠΌΡƒ ΠΈΠΌΠ΅Π½Π½ΠΎ Π² Ρ‚Π°ΠΊΠΎΠΌ порядкС стоит Π΄Π΅Π»Π°Ρ‚ΡŒ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ? ΠŸΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ ΠΈΠΌΠ΅Π½Π½ΠΎ Ρ‚Π°ΠΊ Ρ€Π°Π·ΠΌΠ΅Ρ€ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ вырастСт минимально (ΠΏΠΎΠΌΠ½ΠΈ ΠΏΡ€ΠΎ MVCC!).

DELETE FROM dst

НСт, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ±ΠΎΠΉΡ‚ΠΈΡΡŒ всСго двумя опСрациями:

  • ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ (DELETE) Π²ΠΎΠΎΠ±Ρ‰Π΅ всС
  • Π²ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ всС ΠΈΠ· Π½ΠΎΠ²ΠΎΠ³ΠΎ ΠΎΠ±Ρ€Π°Π·Π°

Но ΠΏΡ€ΠΈ этом, благодаря MVCC, Ρ€Π°Π·ΠΌΠ΅Ρ€ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ увСличится Ρ€ΠΎΠ²Π½ΠΎ Π² Π΄Π²Π° Ρ€Π°Π·Π°! ΠŸΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ +1M ΠΎΠ±Ρ€Π°Π·ΠΎΠ² записСй Π² Ρ‚Π°Π±Π»ΠΈΡ†Π΅ ΠΈΠ·-Π·Π° обновлСния 10K β€” Ρ‚Π°ΠΊ сСбС ΠΈΠ·Π±Ρ‹Ρ‚ΠΎΡ‡Π½ΠΎΡΡ‚ΡŒβ€¦

TRUNCATE dst

Π‘ΠΎΠ»Π΅Π΅ ΠΎΠΏΡ‹Ρ‚Π½Ρ‹ΠΉ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Π·Π½Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ всю Ρ‚Π°Π±Π»ΠΈΡ‡ΠΊΡƒ Ρ†Π΅Π»ΠΈΠΊΠΎΠΌ ΠΌΠΎΠΆΠ½ΠΎ достаточно дСшСво Π·Π°Ρ‡ΠΈΡΡ‚ΠΈΡ‚ΡŒ:

  • ΠΎΡ‡ΠΈΡΡ‚ΠΈΡ‚ΡŒ (TRUNCATE) Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ Ρ†Π΅Π»ΠΈΠΊΠΎΠΌ
  • Π²ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ всС ΠΈΠ· Π½ΠΎΠ²ΠΎΠ³ΠΎ ΠΎΠ±Ρ€Π°Π·Π°

ΠœΠ΅Ρ‚ΠΎΠ΄ дСйствСнный, ΠΈΠ½ΠΎΠ³Π΄Π° Π²ΠΏΠΎΠ»Π½Π΅ ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΠΌ, Π½ΠΎ Π΅ΡΡ‚ΡŒ нСзадача… Π’Π»ΠΈΠ²Π°Ρ‚ΡŒ 1M записСй ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Π΄ΠΎ-ΠΎ-ΠΎΠ»Π³ΠΎ, поэтому ΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ пустой Π½Π° всС это врСмя (ΠΊΠ°ΠΊ ΠΏΡ€ΠΎΠΈΠ·ΠΎΠΉΠ΄Π΅Ρ‚ Π±Π΅Π· оборачивания Π² Π΅Π΄ΠΈΠ½ΡƒΡŽ Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΡŽ) Π½Π΅ ΠΌΠΎΠΆΠ΅ΠΌ сСбС ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΡ‚ΡŒ.

А Π·Π½Π°Ρ‡ΠΈΡ‚:

  • Ρƒ нас начинаСтся Π΄Π»ΠΈΡ‚Π΅Π»ΡŒΠ½Π°Ρ транзакция
  • TRUNCATE Π½Π°ΠΊΠ»Π°Π΄Ρ‹Π²Π°Π΅Ρ‚ AccessExclusive-Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΊΡƒ
  • ΠΌΡ‹ Π΄ΠΎΠ»Π³ΠΎ Π΄Π΅Π»Π°Π΅ΠΌ вставку, Π° всС ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ Π² это врСмя Π½Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π΄Π°ΠΆΠ΅ SELECT

Π§Π΅-Ρ‚ΠΎ Π½Π΅Ρ…ΠΎΡ€ΠΎΡˆΠΎ получаСтся…

ALTER TABLE… RENAME… / DROP TABLE …

Как Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ β€” Π·Π°Π»ΠΈΡ‚ΡŒ всС Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΡƒΡŽ Π½ΠΎΠ²ΡƒΡŽ Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ, Π° ΠΏΠΎΡ‚ΠΎΠΌ просто ΠΏΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Ρ‚ΡŒ Π½Π° мСсто старой. ΠŸΠ°Ρ€Π° ΠΏΡ€ΠΎΡ‚ΠΈΠ²Π½Ρ‹Ρ… ΠΌΠ΅Π»ΠΎΡ‡Π΅ΠΉ:

  • Ρ‚Π°ΠΊΠΈ Ρ‚ΠΎΠΆΠ΅ AccessExclusive, Ρ…ΠΎΡ‚ΡŒ ΠΈ сущСствСнно мСньшС ΠΏΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ
  • ΡΠ±Ρ€Π°ΡΡ‹Π²Π°ΡŽΡ‚ΡΡ всС ΠΏΠ»Π°Π½Ρ‹ запросов/статистика этой Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹, Π½Π°Π΄ΠΎ Π³ΠΎΠ½ΡΡ‚ΡŒ ANALYZE
  • Π»ΠΎΠΌΠ°ΡŽΡ‚ΡΡ всС внСшниС ΠΊΠ»ΡŽΡ‡ΠΈ (FK) Π½Π° Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ

Π‘Ρ‹Π» WIP-ΠΏΠ°Ρ‚Ρ‡ ΠΎΡ‚ Simon Riggs, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΡ€Π΅Π΄Π»Π°Π³Π°Π» ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ALTER-ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ для ΠΏΠΎΠ΄ΠΌΠ΅Π½Ρ‹ Ρ‚Π΅Π»Π° Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π½Π° Ρ„Π°ΠΉΠ»ΠΎΠ²ΠΎΠΌ ΡƒΡ€ΠΎΠ²Π½Π΅, Π½Π΅ трогая статистику ΠΈ FK, Π½ΠΎ Π½Π΅ собрал ΠΊΠ²ΠΎΡ€ΡƒΠΌΠ°.

DELETE, UPDATE, INSERT

Π˜Ρ‚Π°ΠΊ, останавливаСмся Π½Π° Π½Π΅Π±Π»ΠΎΠΊΠΈΡ€ΡƒΡŽΡ‰Π΅ΠΌ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π΅ ΠΈΠ· Ρ‚Ρ€Π΅Ρ… ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ. ΠŸΠΎΡ‡Ρ‚ΠΈ трСх… Как это ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π½Π°ΠΈΠ±ΠΎΠ»Π΅Π΅ эффСктивно?

-- всС Π΄Π΅Π»Π°Π΅ΠΌ Π² Ρ€Π°ΠΌΠΊΠ°Ρ… Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΈ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½ΠΈΠΊΡ‚ΠΎ Π½Π΅ Π²ΠΈΠ΄Π΅Π» "ΠΏΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΎΡ‡Π½Ρ‹Ρ…" состояний
BEGIN;

-- создаСм Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ с ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΠ΅ΠΌΡ‹ΠΌΠΈ Π΄Π°Π½Π½Ρ‹ΠΌΠΈ
CREATE TEMPORARY TABLE tmp(
  LIKE dst INCLUDING INDEXES -- ΠΏΠΎ ΠΎΠ±Ρ€Π°Π·Ρƒ ΠΈ подобию, вмСстС с индСксами
) ON COMMIT DROP; -- Π·Π° Ρ€Π°ΠΌΠΊΠ°ΠΌΠΈ Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΈ ΠΎΠ½Π° Π½Π°ΠΌ Π½Π΅ Π½ΡƒΠΆΠ½Π°

-- быстро-быстро Π²Π»ΠΈΠ²Π°Π΅ΠΌ Π½ΠΎΠ²Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π· Ρ‡Π΅Ρ€Π΅Π· COPY
COPY tmp FROM STDIN;
-- ...
-- .

-- удаляСм ΠΎΡ‚ΡΡƒΡ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅
DELETE FROM
  dst D
USING
  dst X
LEFT JOIN
  tmp Y
    USING(pk1, pk2) -- поля ΠΏΠ΅Ρ€Π²ΠΈΡ‡Π½ΠΎΠ³ΠΎ ΠΊΠ»ΡŽΡ‡Π°
WHERE
  (D.pk1, D.pk2) = (X.pk1, X.pk2) AND
  Y IS NOT DISTINCT FROM NULL; -- "Π°Π½Ρ‚ΠΈΠ΄ΠΆΠΎΠΉΠ½"

-- обновляСм ΠΎΡΡ‚Π°Π²ΡˆΠΈΠ΅ΡΡ
UPDATE
  dst D
SET
  (f1, f2, f3) = (T.f1, T.f2, T.f3)
FROM
  tmp T
WHERE
  (D.pk1, D.pk2) = (T.pk1, T.pk2) AND
  (D.f1, D.f2, D.f3) IS DISTINCT FROM (T.f1, T.f2, T.f3); -- Π½Π΅Π·Π°Ρ‡Π΅ΠΌ ΠΎΠ±Π½ΠΎΠ²Π»ΡΡ‚ΡŒ ΡΠΎΠ²ΠΏΠ°Π΄Π°ΡŽΡ‰ΠΈΠ΅

-- вставляСм ΠΎΡ‚ΡΡƒΡ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅
INSERT INTO
  dst
SELECT
  T.*
FROM
  tmp T
LEFT JOIN
  dst D
    USING(pk1, pk2)
WHERE
  D IS NOT DISTINCT FROM NULL;

COMMIT;

3.2. ΠŸΠΎΡΡ‚ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ΠΈΠΌΠΏΠΎΡ€Ρ‚Π°

Π’ Ρ‚ΠΎΠΌ ΠΆΠ΅ самом ΠšΠ›ΠΠ”Π Π΅ всС измСнившиСся записи Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΏΡ€ΠΎΠ³Π½Π°Ρ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· постобработку β€” Π½ΠΎΡ€ΠΌΠ°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ, Π²Ρ‹Π΄Π΅Π»ΠΈΡ‚ΡŒ ΠΊΠ»ΡŽΡ‡Π΅Π²Ρ‹Π΅ слова, привСсти ΠΊ Π½ΡƒΠΆΠ½Ρ‹ΠΌ структурам. Но ΠΊΠ°ΠΊ ΡƒΠ·Π½Π°Ρ‚ΡŒ β€” Ρ‡Ρ‚ΠΎ ΠΈΠΌΠ΅Π½Π½ΠΎ измСнялось, Π½Π΅ услоТняя ΠΏΡ€ΠΈ этом ΠΊΠΎΠ΄ синхронизации, Π² ΠΈΠ΄Π΅Π°Π»Π΅, Π²ΠΎΠΎΠ±Ρ‰Π΅ Π½Π΅ трогая Π΅Π³ΠΎ?

Если доступ Π½Π° запись Π² ΠΌΠΎΠΌΠ΅Π½Ρ‚ синхронизации Π΅ΡΡ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρƒ вашСго процСсса, Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ Ρ‚Ρ€ΠΈΠ³Π³Π΅Ρ€ΠΎΠΌ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ собСрСт для нас всС измСнСния:

-- Ρ†Π΅Π»Π΅Π²Ρ‹Π΅ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹
CREATE TABLE kladr(...);
CREATE TABLE kladr_house(...);

-- Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ с историСй ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ
CREATE TABLE kladr$log(
  ro kladr, -- Ρ‚ΡƒΡ‚ Π»Π΅ΠΆΠ°Ρ‚ Ρ†Π΅Π»Ρ‹Π΅ ΠΎΠ±Ρ€Π°Π·Ρ‹ записСй старой/Π½ΠΎΠ²ΠΎΠΉ
  rn kladr
);

CREATE TABLE kladr_house$log(
  ro kladr_house,
  rn kladr_house
);

-- общая функция логирования ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ
CREATE OR REPLACE FUNCTION diff$log() RETURNS trigger AS $$
DECLARE
  dst varchar = TG_TABLE_NAME || '$log';
  stmt text = '';
BEGIN
  -- провСряСм Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ логгирования ΠΏΡ€ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΈ записи
  IF TG_OP = 'UPDATE' THEN
    IF NEW IS NOT DISTINCT FROM OLD THEN
      RETURN NEW;
    END IF;
  END IF;
  -- создаСм запись лога
  stmt = 'INSERT INTO ' || dst::text || '(ro,rn)VALUES(';
  CASE TG_OP
    WHEN 'INSERT' THEN
      EXECUTE stmt || 'NULL,$1)' USING NEW;
    WHEN 'UPDATE' THEN
      EXECUTE stmt || '$1,$2)' USING OLD, NEW;
    WHEN 'DELETE' THEN
      EXECUTE stmt || '$1,NULL)' USING OLD;
  END CASE;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠ΅Ρ€Π΅Π΄ Π½Π°Ρ‡Π°Π»ΠΎΠΌ синхронизации Ρ‚Ρ€ΠΈΠ³Π³Π΅Ρ€Ρ‹ Π½Π°Π»ΠΎΠΆΠΈΡ‚ΡŒ (ΠΈΠ»ΠΈ Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· ALTER TABLE ... ENABLE TRIGGER ...):

CREATE TRIGGER log
  AFTER INSERT OR UPDATE OR DELETE
  ON kladr
    FOR EACH ROW
      EXECUTE PROCEDURE diff$log();

CREATE TRIGGER log
  AFTER INSERT OR UPDATE OR DELETE
  ON kladr_house
    FOR EACH ROW
      EXECUTE PROCEDURE diff$log();

А ΠΏΠΎΡ‚ΠΎΠΌ спокойно ΠΈΠ· log-Ρ‚Π°Π±Π»ΠΈΡ† ΠΈΠ·Π²Π»Π΅ΠΊΠ°Π΅ΠΌ всС Π½ΡƒΠΆΠ½Ρ‹Π΅ Π½Π°ΠΌ измСнСния ΠΈ прогоняСм ΠΏΠΎ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°ΠΌ.

3.3. Π˜ΠΌΠΏΠΎΡ€Ρ‚ связанных Π½Π°Π±ΠΎΡ€ΠΎΠ²

Π’Ρ‹ΡˆΠ΅ ΠΌΡ‹ рассматривали случаи, ΠΊΠΎΠ³Π΄Π° структуры Π΄Π°Π½Π½Ρ‹Ρ… источника ΠΈ ΠΏΡ€ΠΈΠ΅ΠΌΠ½ΠΈΠΊΠ° ΡΠΎΠ²ΠΏΠ°Π΄Π°ΡŽΡ‚. Но Ρ‡Ρ‚ΠΎ Π΄Π΅Π»Π°Ρ‚ΡŒ, Ссли Π²Ρ‹Π³Ρ€ΡƒΠ·ΠΊΠ° ΠΈΠ· внСшнСй систСмы ΠΈΠΌΠ΅Π΅Ρ‚ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ ΠΎΡ‚Π»ΠΈΡ‡Π½Ρ‹ΠΉ ΠΎΡ‚ структуры хранСния Ρƒ нас Π² Π±Π°Π·Π΅?

Π’ΠΎΠ·ΡŒΠΌΠ΅ΠΌ Π² качСствС ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° Ρ…Ρ€Π°Π½Π΅Π½ΠΈΠ΅ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΎΠ² ΠΈ счСтов ΠΏΠΎ Π½ΠΈΠΌ, классичСский Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ Β«ΠΌΠ½ΠΎΠ³ΠΈΠ΅-ΠΊ-ΠΎΠ΄Π½ΠΎΠΌΡƒΒ»:

CREATE TABLE client(
  client_id
    serial
      PRIMARY KEY
, inn
    varchar
      UNIQUE
, name
    varchar
);

CREATE TABLE invoice(
  invoice_id
    serial
      PRIMARY KEY
, client_id
    integer
      REFERENCES client(client_id)
, number
    varchar
, dt
    date
, sum
    numeric(32,2)
);

А Π²ΠΎΡ‚ Π²Ρ‹Π³Ρ€ΡƒΠ·ΠΊΠ° ΠΈΠ· внСшнСго источника ΠΏΡ€ΠΈΡ…ΠΎΠ΄ΠΈΡ‚ Π½Π°ΠΌ Π² Π²ΠΈΠ΄Π΅ «всС Π² ΠΎΠ΄Π½ΠΎΠΌΒ»:

CREATE TEMPORARY TABLE invoice_import(
  client_inn
    varchar
, client_name
    varchar
, invoice_number
    varchar
, invoice_dt
    date
, invoice_sum
    numeric(32,2)
);

ΠžΡ‡Π΅Π²ΠΈΠ΄Π½ΠΎ, Ρ‡Ρ‚ΠΎ Π΄Π°Π½Π½Ρ‹Π΅ ΠΏΠΎ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°ΠΌ ΠΌΠΎΠ³ΡƒΡ‚ Π΄ΡƒΠ±Π»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ Π² Ρ‚Π°ΠΊΠΎΠΌ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π΅, Π° основной записью являСтся «счСт»:

0123456789;Вася;A-01;2020-03-16;1000.00
9876543210;ΠŸΠ΅Ρ‚Ρ;A-02;2020-03-16;666.00
0123456789;Вася;B-03;2020-03-16;9999.00

Для ΠΌΠΎΠ΄Π΅Π»ΠΈ просто вставим наши тСстовыС Π΄Π°Π½Π½Ρ‹Π΅, Π½ΠΎ ΠΏΠΎΠΌΠ½ΠΈΠΌ β€” COPY эффСктивнСС!

INSERT INTO invoice_import
VALUES
  ('0123456789', 'Вася', 'A-01', '2020-03-16', 1000.00)
, ('9876543210', 'ΠŸΠ΅Ρ‚Ρ', 'A-02', '2020-03-16', 666.00)
, ('0123456789', 'Вася', 'B-03', '2020-03-16', 9999.00);

Π‘Π½Π°Ρ‡Π°Π»Π° Π²Ρ‹Π΄Π΅Π»ΠΈΠΌ Ρ‚Π΅ Β«Ρ€Π°Π·Ρ€Π΅Π·Ρ‹Β», Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ наши Β«Ρ„Π°ΠΊΡ‚Ρ‹Β» ΡΡΡ‹Π»Π°ΡŽΡ‚ΡΡ. Π’ нашСм случаС счСта ΡΡΡ‹Π»Π°ΡŽΡ‚ΡΡ Π½Π° ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΎΠ²:

CREATE TEMPORARY TABLE client_import AS
SELECT DISTINCT ON(client_inn)
-- ΠΌΠΎΠΆΠ½ΠΎ просто SELECT DISTINCT, Ссли Π΄Π°Π½Π½Ρ‹Π΅ Π·Π°Π²Π΅Π΄ΠΎΠΌΠΎ Π½Π΅ΠΏΡ€ΠΎΡ‚ΠΈΠ²ΠΎΡ€Π΅Ρ‡ΠΈΠ²Ρ‹
  client_inn inn
, client_name "name"
FROM
  invoice_import;

Π§Ρ‚ΠΎΠ±Ρ‹ счСта ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ ΡΠ²ΡΠ·Π°Ρ‚ΡŒ с ID ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΎΠ², Π½Π°ΠΌ эти ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€Ρ‹ Π½Π°Π΄ΠΎ сначала ΡƒΠ·Π½Π°Ρ‚ΡŒ ΠΈΠ»ΠΈ ΡΠ³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ. Π”ΠΎΠ±Π°Π²ΠΈΠΌ ΠΏΠΎΠ΄ Π½ΠΈΡ… поля:

ALTER TABLE invoice_import ADD COLUMN client_id integer;
ALTER TABLE client_import ADD COLUMN client_id integer;

Π’ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡΡ описанным Π²Ρ‹ΡˆΠ΅ способом синхронизации Ρ‚Π°Π±Π»ΠΈΡ† с нСбольшой ΠΏΠΎΠΏΡ€Π°Π²ΠΊΠΎΠΉ β€” Π½Π΅ Π±ΡƒΠ΄Π΅ΠΌ Π½ΠΈΡ‡Π΅Π³ΠΎ ΠΎΠ±Π½ΠΎΠ²Π»ΡΡ‚ΡŒ ΠΈ ΡƒΠ΄Π°Π»ΡΡ‚ΡŒ Π² Ρ†Π΅Π»Π΅Π²ΠΎΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Π΅, вСдь ΠΈΠΌΠΏΠΎΡ€Ρ‚ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΎΠ² Ρƒ нас Β«append-onlyΒ»:

-- проставляСм Π² Ρ‚Π°Π±Π»ΠΈΡ†Π΅ ΠΈΠΌΠΏΠΎΡ€Ρ‚Π° ID ΡƒΠΆΠ΅ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΡ… записСй
UPDATE
  client_import T
SET
  client_id = D.client_id
FROM
  client D
WHERE
  T.inn = D.inn; -- unique key

-- вставляСм ΠΎΡ‚ΡΡƒΡ‚ΡΡ‚Π²ΠΎΠ²Π°Π²ΡˆΠΈΠ΅ записи ΠΈ проставляСм ΠΈΡ… ID
WITH ins AS (
  INSERT INTO client(
    inn
  , name
  )
  SELECT
    inn
  , name
  FROM
    client_import
  WHERE
    client_id IS NULL -- Ссли ID Π½Π΅ проставился
  RETURNING *
)
UPDATE
  client_import T
SET
  client_id = D.client_id
FROM
  ins D
WHERE
  T.inn = D.inn; -- unique key

-- проставляСм ID ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΎΠ² Ρƒ записСй счСтов
UPDATE
  invoice_import T
SET
  client_id = D.client_id
FROM
  client_import D
WHERE
  T.client_inn = D.inn; -- ΠΏΡ€ΠΈΠΊΠ»Π°Π΄Π½ΠΎΠΉ ΠΊΠ»ΡŽΡ‡

БобствСнно, всС β€” Π² invoice_import Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ Ρƒ нас Π·Π°ΠΏΠΎΠ»Π½Π΅Π½ΠΎ ΠΏΠΎΠ»Π΅ связи client_id, с ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ ΠΌΡ‹ ΠΈ вставим счСт.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com