ΠžΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½Π°Ρ Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠ° Π² микросСрвисной Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π΅: ΠΏΜΆΠΎΜΆΠ½ΜΆΡΜΆΡ‚ΜΆΡŒΜΆ ΜΆΠΈΜΆ ΜΆΠΏΜΆΡ€ΜΆΠΎΜΆΡΜΆΡ‚ΜΆΠΈΜΆΡ‚ΜΆΡŒΜΆ ΠΏΠΎΠΌΠΎΡ‡ΡŒ ΠΈ ΠΏΠΎΠ΄ΡΠΊΠ°Π·Π°Ρ‚ΡŒ Postgres FDW

ΠœΠΈΠΊΡ€ΠΎΡΠ΅Ρ€Π²ΠΈΡΠ½Π°Ρ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π°, ΠΊΠ°ΠΊ ΠΈ всС Π² этом ΠΌΠΈΡ€Π΅, ΠΈΠΌΠ΅Π΅Ρ‚ свои ΠΏΠ»ΡŽΡΡ‹ ΠΈ свои минусы. Одни процСссы с Π½Π΅ΠΉ становятся ΠΏΡ€ΠΎΡ‰Π΅, Π΄Ρ€ΡƒΠ³ΠΈΠ΅ β€” слоТнСС. И Π² ΡƒΠ³ΠΎΠ΄Ρƒ скорости ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ ΠΈ Π»ΡƒΡ‡ΡˆΠ΅ΠΉ ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΈΡ€ΡƒΠ΅ΠΌΠΎΡΡ‚ΠΈ Π½ΡƒΠΆΠ½ΠΎ ΠΏΡ€ΠΈΠ½ΠΎΡΠΈΡ‚ΡŒ свои ΠΆΠ΅Ρ€Ρ‚Π²Ρ‹. Одна ΠΈΠ· Π½ΠΈΡ… β€” услоТнСниС Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠΈ. Если Π² ΠΌΠΎΠ½ΠΎΠ»ΠΈΡ‚Π΅ всю ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΡƒΡŽ Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΡƒ ΠΌΠΎΠΆΠ½ΠΎ свСсти ΠΊ SQL запросам ΠΊ аналитичСской Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ΅, Ρ‚ΠΎ Π² ΠΌΡƒΠ»ΡŒΡ‚ΠΈΡΠ΅Ρ€Π²ΠΈΡΠ½ΠΎΠΉ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π΅ Ρƒ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ сСрвиса своя Π±Π°Π·Π° ΠΈ, каТСтся, Ρ‡Ρ‚ΠΎ ΠΎΠ΄Π½ΠΈΠΌ запросом Π½Π΅ ΠΎΠ±ΠΎΠΉΡ‚ΠΈΡΡŒ (Π° ΠΌΠΎΠΆΠ΅Ρ‚ ΠΎΠ±ΠΎΠΉΡ‚ΠΈΡΡŒ?). Для Ρ‚Π΅Ρ…, ΠΊΠΎΠΌΡƒ интСрСсно, ΠΊΠ°ΠΊ ΠΌΡ‹ Ρ€Π΅ΡˆΠΈΠ»ΠΈ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΠΉ Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠΈ Ρƒ сСбя Π² ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ ΠΈ ΠΊΠ°ΠΊ Π½Π°ΡƒΡ‡ΠΈΠ»ΠΈΡΡŒ ΠΆΠΈΡ‚ΡŒ с этим Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ΠΌ β€” welcome.

ΠžΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½Π°Ρ Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠ° Π² микросСрвисной Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π΅: ΠΏΜΆΠΎΜΆΠ½ΜΆΡΜΆΡ‚ΜΆΡŒΜΆ ΜΆΠΈΜΆ ΜΆΠΏΜΆΡ€ΜΆΠΎΜΆΡΜΆΡ‚ΜΆΠΈΜΆΡ‚ΜΆΡŒΜΆ ΠΏΠΎΠΌΠΎΡ‡ΡŒ ΠΈ ΠΏΠΎΠ΄ΡΠΊΠ°Π·Π°Ρ‚ΡŒ Postgres FDW
МСня Π·ΠΎΠ²ΡƒΡ‚ ПавСл Биваш, Π² Π”ΠΎΠΌΠšΠ»ΠΈΠΊΠ΅ я Ρ€Π°Π±ΠΎΡ‚Π°ΡŽ Π² ΠΊΠΎΠΌΠ°Π½Π΄Π΅, которая ΠΎΡ‚Π²Π΅Ρ‡Π°Π΅Ρ‚ Π·Π° сопровоТдСниС аналитичСского Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π° Π΄Π°Π½Π½Ρ‹Ρ…. Условно Π½Π°ΡˆΡƒ Π΄Π΅ΡΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ ΠΌΠΎΠΆΠ½ΠΎ отнСсти ΠΊ Π΄Π°Ρ‚Π° ΠΈΠ½ΠΆΠ΅Π½Π΅Ρ€ΠΈΠΈ, Π½ΠΎ, Π½Π° самом Π΄Π΅Π»Π΅, спСктр Π·Π°Π΄Π°Ρ‡ Π³ΠΎΡ€Π°Π·Π΄ΠΎ ΡˆΠΈΡ€Π΅. Π•ΡΡ‚ΡŒ стандартныС для Π΄Π°Ρ‚Π° ΠΈΠ½ΠΆΠ΅Π½Π΅Ρ€ΠΈΠΈ ETL/ELT, ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° ΠΈ адаптация инструмСнтов для Π°Π½Π°Π»ΠΈΠ·Π° Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° своих инструмСнтов. Π’ частности, для ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΠΉ отчСтности ΠΌΡ‹ Ρ€Π΅ΡˆΠΈΠ»ΠΈ Β«ΠΏΡ€ΠΈΡ‚Π²ΠΎΡ€ΠΈΡ‚ΡŒΡΡΒ», Ρ‡Ρ‚ΠΎ Ρƒ нас ΠΌΠΎΠ½ΠΎΠ»ΠΈΡ‚ ΠΈ Π΄Π°Ρ‚ΡŒ Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠ°ΠΌ ΠΎΠ΄Π½Ρƒ Π±Π°Π·Ρƒ, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π±ΡƒΠ΄ΡƒΡ‚ всС Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ ΠΈΠΌ Π΄Π°Π½Π½Ρ‹Π΅.

Π’ΠΎΠΎΠ±Ρ‰Π΅, ΠΌΡ‹ рассматривали Ρ€Π°Π·Π½Ρ‹Π΅ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Ρ‹. МоТно Π±Ρ‹Π»ΠΎ ΠΏΠΎΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΏΠΎΠ»Π½ΠΎΡ†Π΅Π½Π½ΠΎΠ΅ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅ β€” ΠΌΡ‹ Π΄Π°ΠΆΠ΅ ΠΏΡ€ΠΎΠ±ΠΎΠ²Π°Π»ΠΈ, Π½ΠΎ, Ссли чСстно, Ρ‚Π°ΠΊ ΠΈ Π½Π΅ ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΏΠΎΠ΄Ρ€ΡƒΠΆΠΈΡ‚ΡŒ достаточно частыС измСнСния Π² Π»ΠΎΠ³ΠΈΠΊΠ΅ с достаточно ΠΌΠ΅Π΄Π»Π΅Π½Π½Ρ‹ΠΌ процСссом построСния Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π° ΠΈ внСсСния Π² Π½Π΅Π³ΠΎ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ (Ссли Ρƒ ΠΊΠΎΠ³ΠΎ-Ρ‚ΠΎ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΎΡΡŒ, Π½Π°ΠΏΠΈΡˆΠΈΡ‚Π΅ Π² коммСнтариях ΠΊΠ°ΠΊ). МоТно Π±Ρ‹Π»ΠΎ ΡΠΊΠ°Π·Π°Ρ‚ΡŒ Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠ°ΠΌ: «РСбята, ΡƒΡ‡ΠΈΡ‚Π΅ python ΠΈ Ρ…ΠΎΠ΄ΠΈΡ‚Π΅ Π² аналитичСскиС Ρ€Π΅ΠΏΠ»ΠΈΠΊΠΈΒ», Π½ΠΎ это Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΊ ΠΏΠΎΠ΄Π±ΠΎΡ€Ρƒ пСрсонала, ΠΈ казалось, Ρ‡Ρ‚ΠΎ этого стоит ΠΈΠ·Π±Π΅ΠΆΠ°Ρ‚ΡŒ, Ссли Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ. РСшили ΠΏΠΎΠΏΡ€ΠΎΠ±ΠΎΠ²Π°Ρ‚ΡŒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΡŽ FDW (Foreign Data Wrapper): ΠΏΠΎ сути, это стандартный dblink, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π΅ΡΡ‚ΡŒ Π² стандартС SQL, Π½ΠΎ со своим Π³ΠΎΡ€Π°Π·Π΄ΠΎ Π±ΠΎΠ»Π΅Π΅ ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΌ интСрфСйсом. На Π±Π°Π·Π΅ Π½Π΅Π΅ ΠΌΡ‹ сдСлали Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π² ΠΈΡ‚ΠΎΠ³Π΅ ΠΈ ΠΏΡ€ΠΈΠΆΠΈΠ»ΠΎΡΡŒ, Π½Π° Π½Π΅ΠΌ ΠΌΡ‹ ΠΎΡΡ‚Π°Π½ΠΎΠ²ΠΈΠ»ΠΈΡΡŒ. Π•Π³ΠΎ подробности β€” Ρ‚Π΅ΠΌΠ° ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠΉ ΡΡ‚Π°Ρ‚ΡŒΠΈ, Π° ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈ Π½Π΅ ΠΎΠ΄Π½ΠΎΠΉ, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Ρ€Π°ΡΡΠΊΠ°Π·Π°Ρ‚ΡŒ хочСтся ΠΎ ΠΌΠ½ΠΎΠ³ΠΎΠΌ: ΠΎΡ‚ синхронизации схСм Π±Π°Π· Π΄ΠΎ управлСния доступом ΠΈ обСзличивания ΠΏΠ΅Ρ€ΡΠΎΠ½Π°Π»ΡŒΠ½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ…. Π’Π°ΠΊΠΆΠ΅ Π½ΡƒΠΆΠ½ΠΎ ΠΎΠ³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ΡŒΡΡ, Ρ‡Ρ‚ΠΎ это Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ Π½Π΅ являСтся Π·Π°ΠΌΠ΅Π½ΠΎΠΉ Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹ΠΌ аналитичСским Π±Π°Π·Π°ΠΌ ΠΈ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π°ΠΌ, ΠΎΠ½ΠΎ Ρ€Π΅ΡˆΠ°Π΅Ρ‚ лишь ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΡƒΡŽ Π·Π°Π΄Π°Ρ‡Ρƒ.

Π’Π΅Ρ€Ρ…Π½Π΅ΡƒΡ€ΠΎΠ²Π½Π΅Π²ΠΎ это выглядит Ρ‚Π°ΠΊ:

ΠžΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½Π°Ρ Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠ° Π² микросСрвисной Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π΅: ΠΏΜΆΠΎΜΆΠ½ΜΆΡΜΆΡ‚ΜΆΡŒΜΆ ΜΆΠΈΜΆ ΜΆΠΏΜΆΡ€ΜΆΠΎΜΆΡΜΆΡ‚ΜΆΠΈΜΆΡ‚ΜΆΡŒΜΆ ΠΏΠΎΠΌΠΎΡ‡ΡŒ ΠΈ ΠΏΠΎΠ΄ΡΠΊΠ°Π·Π°Ρ‚ΡŒ Postgres FDW
Π•ΡΡ‚ΡŒ Π±Π°Π·Π° PostgreSQL, Ρ‚Π°ΠΌ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΠΈ ΠΌΠΎΠ³ΡƒΡ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ свои Ρ€Π°Π±ΠΎΡ‡ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹Π΅, Π° самоС Π²Π°ΠΆΠ½ΠΎΠ΅ β€” ΠΊ этой Π±Π°Π·Π΅ Ρ‡Π΅Ρ€Π΅Π· FDW ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½Ρ‹ аналитичСскиС Ρ€Π΅ΠΏΠ»ΠΈΠΊΠΈ всСх сСрвисов. Π­Ρ‚ΠΎ Π΄Π°Π΅Ρ‚ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ запрос ΠΊ нСскольким Π±Π°Π·Π°ΠΌ, ΠΏΡ€ΠΈΡ‡Π΅ΠΌ Π½Π΅Π²Π°ΠΆΠ½ΠΎ, Ρ‡Ρ‚ΠΎ это: PostgreSQL, MySQL, MongoDB ΠΈΠ»ΠΈ Π΅Ρ‰Π΅ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ (Ρ„Π°ΠΉΠ», API, Ссли Π²Π΄Ρ€ΡƒΠ³ Π½Π΅Ρ‚ подходящСго Π²Ρ€Π°ΠΏΠΏΠ΅Ρ€Π°, ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ свой). Ну Π²Ρ€ΠΎΠ΄Π΅ всС, супСр! Расходимся?

Если Π±Ρ‹ всС Π·Π°ΠΊΠ°Π½Ρ‡ΠΈΠ²Π°Π»ΠΎΡΡŒ Ρ‚Π°ΠΊ быстро ΠΈ просто, Ρ‚ΠΎ, Π½Π°Π²Π΅Ρ€Π½ΠΎΠ΅, ΡΡ‚Π°Ρ‚ΡŒΠΈ Π±Ρ‹ ΠΈ Π½Π΅ Π±Ρ‹Π»ΠΎ.

Π’Π°ΠΆΠ½ΠΎ Ρ‡Π΅Ρ‚ΠΊΠΎ ΠΎΡΠΎΠ·Π½Π°Π²Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊ постгрСс ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ запросы ΠΊ ΡƒΠ΄Π°Π»Π΅Π½Π½Ρ‹ΠΌ сСрвСрам. Π­Ρ‚ΠΎ каТСтся Π»ΠΎΠ³ΠΈΡ‡Π½Ρ‹ΠΌ, ΠΎΠ΄Π½Π°ΠΊΠΎ Π·Π°Ρ‡Π°ΡΡ‚ΡƒΡŽ Π½Π° это Π½Π΅ ΠΎΠ±Ρ€Π°Ρ‰Π°ΡŽΡ‚ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅: постгрСс Π΄Π΅Π»ΠΈΡ‚ запрос Π½Π° части, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡŽΡ‚ΡΡ Π½Π° ΡƒΠ΄Π°Π»Π΅Π½Π½Ρ‹Ρ… сСрвСрах нСзависимо, собираСт эти Π΄Π°Π½Π½Ρ‹Π΅, Π° Ρ„ΠΈΠ½Π°Π»ΡŒΠ½Ρ‹Π΅ вычислСния ΠΏΡ€ΠΎΠ²ΠΎΠ΄ΠΈΡ‚ ΡƒΠΆΠ΅ сам, поэтому ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ выполнСния запроса Π±ΡƒΠ΄Π΅Ρ‚ сильно Π·Π°Π²ΠΈΡΠ΅Ρ‚ΡŒ ΠΎΡ‚ Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ ΠΎΠ½ написан. Π‘Π»Π΅Π΄ΡƒΠ΅Ρ‚ Ρ‚Π°ΠΊ ΠΆΠ΅ ΠΎΡ‚ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ: ΠΊΠΎΠ³Π΄Π° Π΄Π°Π½Π½Ρ‹Π΅ ΠΏΠΎΡΡ‚ΡƒΠΏΠ°ΡŽΡ‚ с ΡƒΠ΄Π°Π»Π΅Π½Π½ΠΎΠ³ΠΎ сСрвСра Ρƒ Π½ΠΈΡ… ΡƒΠΆΠ΅ Π½Π΅Ρ‚ индСксов, Π½Π΅Ρ‚ Π½ΠΈΡ‡Π΅Π³ΠΎ, Ρ‡Ρ‚ΠΎ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠ»Π°Π½ΠΈΡ€ΠΎΠ²Ρ‰ΠΈΠΊΡƒ, ΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ, ΠΏΠΎΠΌΠΎΡ‡ΡŒ ΠΈ ΠΏΠΎΠ΄ΡΠΊΠ°Π·Π°Ρ‚ΡŒ Π΅ΠΌΡƒ ΠΌΠΎΠΆΠ΅ΠΌ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΌΡ‹ сами. И ΠΈΠΌΠ΅Π½Π½ΠΎ ΠΎΠ± этом хочСтся Ρ€Π°ΡΡΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Π΅Π΅.

ΠŸΡ€ΠΎΡΡ‚ΠΎΠΉ запрос ΠΈ ΠΏΠ»Π°Π½ с Π½ΠΈΠΌ

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊ постгрСс выполняСт запрос ΠΊ Ρ‚Π°Π±Π»ΠΈΡ†Π΅ Π½Π° 6 ΠΌΠΈΠ»Π»ΠΈΠΎΠ½ΠΎΠ² строк Π½Π° ΡƒΠ΄Π°Π»Π΅Π½Π½ΠΎΠΌ сСрвСрС, посмотрим Π½Π° простой ΠΏΠ»Π°Π½.

explain analyze verbose  
SELECT count(1)
FROM fdw_schema.table;

Aggregate  (cost=418383.23..418383.24 rows=1 width=8) (actual time=3857.198..3857.198 rows=1 loops=1)
  Output: count(1)
  ->  Foreign Scan on fdw_schema."table"  (cost=100.00..402376.14 rows=6402838 width=0) (actual time=4.874..3256.511 rows=6406868 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Remote SQL: SELECT NULL FROM fdw_schema.table
Planning time: 0.986 ms
Execution time: 3857.436 ms

ИспользованиС инструкции VERBOSE позволяСт ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ запрос, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½ Π½Π° ΡƒΠ΄Π°Π»Π΅Π½Π½Ρ‹ΠΉ сСрвСр ΠΈ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ для дальнСйшСй ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ (строка RemoteSQL).

ПойдСм Ρ‡ΡƒΡ‚ΡŒ дальшС ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π² наш запрос нСсколько Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΠΎΠ²: ΠΎΠ΄ΠΈΠ½ ΠΏΠΎ boolean полю, ΠΎΠ΄ΠΈΠ½ ΠΏΠΎ Π²Ρ…ΠΎΠΆΠ΄Π΅Π½ΠΈΡŽ timestamp Π² ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π» ΠΈ ΠΎΠ΄ΠΈΠ½ ΠΏΠΎ jsonb.

explain analyze verbose
SELECT count(1)
FROM fdw_schema.table 
WHERE is_active is True
AND created_dt BETWEEN CURRENT_DATE - INTERVAL '7 month' 
AND CURRENT_DATE - INTERVAL '6 month'
AND meta->>'source' = 'test';

Aggregate  (cost=577487.69..577487.70 rows=1 width=8) (actual time=27473.818..25473.819 rows=1 loops=1)
  Output: count(1)
  ->  Foreign Scan on fdw_schema."table"  (cost=100.00..577469.21 rows=7390 width=0) (actual time=31.369..25372.466 rows=1360025 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Filter: (("table".is_active IS TRUE) AND (("table".meta ->> 'source'::text) = 'test'::text) AND ("table".created_dt >= (('now'::cstring)::date - '7 mons'::interval)) AND ("table".created_dt <= ((('now'::cstring)::date)::timestamp with time zone - '6 mons'::interval)))
        Rows Removed by Filter: 5046843
        Remote SQL: SELECT created_dt, is_active, meta FROM fdw_schema.table
Planning time: 0.665 ms
Execution time: 27474.118 ms

Π’ΠΎΡ‚ ΠΈΠΌΠ΅Π½Π½ΠΎ здСсь ΠΈ кроСтся ΠΌΠΎΠΌΠ΅Π½Ρ‚, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΎΠ±Ρ€Π°Ρ‰Π°Ρ‚ΡŒ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ ΠΏΡ€ΠΈ написании запросов. Π€ΠΈΠ»ΡŒΡ‚Ρ€Ρ‹ Π½Π΅ ΠΏΠ΅Ρ€Π΅Π΄Π°Π»ΠΈΡΡŒ Π½Π° ΡƒΠ΄Π°Π»Π΅Π½Π½Ρ‹ΠΉ сСрвСр, Π° это Π·Π½Π°Ρ‡ΠΈΡ‚, Ρ‡Ρ‚ΠΎ для Π΅Π³ΠΎ выполнСния постгрСс вытягиваСт всС 6 ΠΌΠΈΠ»Π»ΠΈΠΎΠ½ΠΎΠ² строк, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠΆΠ΅ ΠΏΠΎΡ‚ΠΎΠΌ локально ΠΎΡ‚Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΠΎΠ²Π°Ρ‚ΡŒ (строка Filter) ΠΈ произвСсти Π°Π³Ρ€Π΅Π³Π°Ρ†ΠΈΡŽ. Π—Π°Π»ΠΎΠ³ успСха β€” это Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ запрос Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Ρ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Π»ΠΈΡΡŒ Π½Π° ΡƒΠ΄Π°Π»Π΅Π½Π½ΡƒΡŽ ΠΌΠ°ΡˆΠΈΠ½Ρƒ, Π° ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Π»ΠΈ ΠΈ Π°Π³Ρ€Π΅Π³ΠΈΡ€ΠΎΠ²Π°Π»ΠΈ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½ΡƒΠΆΠ½Ρ‹Π΅ строки.

That’s some booleanshit

Π‘ boolean полями β€” всС просто. Π’ исходном запросС ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π»Π° ΠΈΠ·-Π·Π° ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π° is. Если Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π΅Π³ΠΎ Π½Π° =, Ρ‚ΠΎ ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚:

explain analyze verbose
SELECT count(1)
FROM fdw_schema.table
WHERE is_active = True
AND created_dt BETWEEN CURRENT_DATE - INTERVAL '7 month' 
AND CURRENT_DATE - INTERVAL '6 month'
AND meta->>'source' = 'test';

Aggregate  (cost=508010.14..508010.15 rows=1 width=8) (actual time=19064.314..19064.314 rows=1 loops=1)
  Output: count(1)
  ->  Foreign Scan on fdw_schema."table"  (cost=100.00..507988.44 rows=8679 width=0) (actual time=33.035..18951.278 rows=1360025 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Filter: ((("table".meta ->> 'source'::text) = 'test'::text) AND ("table".created_dt >= (('now'::cstring)::date - '7 mons'::interval)) AND ("table".created_dt <= ((('now'::cstring)::date)::timestamp with time zone - '6 mons'::interval)))
        Rows Removed by Filter: 3567989
        Remote SQL: SELECT created_dt, meta FROM fdw_schema.table WHERE (is_active)
Planning time: 0.834 ms
Execution time: 19064.534 ms

Как Π²ΠΈΠ΄ΠΈΡ‚Π΅, Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ ΡƒΠ»Π΅Ρ‚Π΅Π» Π½Π° ΡƒΠ΄Π°Π»Π΅Π½Π½Ρ‹ΠΉ сСрвСр, Π° врСмя выполнСния ΡΠΎΠΊΡ€Π°Ρ‚ΠΈΠ»ΠΎΡΡŒ с 27 Π΄ΠΎ 19 сСкунд.

Π‘Ρ‚ΠΎΠΈΡ‚ ΠΎΡ‚ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ is отличаСтся ΠΎΡ‚ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π° = Ρ‚Π΅ΠΌ, Ρ‡Ρ‚ΠΎ ΡƒΠΌΠ΅Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ со Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ Null. Π­Ρ‚ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ is not True Π² Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π΅ оставит значСния False ΠΈ Null, Ρ‚ΠΎΠ³Π΄Π° ΠΊΠ°ΠΊ != True оставит Ρ‚ΠΎΠ»ΡŒΠΊΠΎ значСния False. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ ΠΏΡ€ΠΈ Π·Π°ΠΌΠ΅Π½Π΅ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π° is not слСдуСт ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ Π² Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ Π΄Π²Π° условия с ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΠΌ OR, ΠΊ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρƒ, WHERE (col != True) OR (col is null).

Π‘ boolean Ρ€Π°Π·ΠΎΠ±Ρ€Π°Π»ΠΈΡΡŒ, двигаСмся дальшС. А ΠΏΠΎΠΊΠ° Π²Π΅Ρ€Π½Π΅ΠΌ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ ΠΏΠΎ Π±ΡƒΠ»Π΅Π²Ρƒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΡŽ Π² ΠΈΠ·Π½Π°Ρ‡Π°Π»ΡŒΠ½Ρ‹ΠΉ Π²ΠΈΠ΄, Ρ‡Ρ‚ΠΎΠ±Ρ‹ нСзависимо Ρ€Π°ΡΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ эффСкт ΠΎΡ‚ Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ.

timestamptz? hz

Π’ΠΎΠΎΠ±Ρ‰Π΅, часто приходится ΡΠΊΡΠΏΠ΅Ρ€ΠΈΠΌΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ с Ρ‚Π΅ΠΌ, ΠΊΠ°ΠΊ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ запрос, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΡƒΡ‡Π°ΡΡ‚Π²ΡƒΡŽΡ‚ ΡƒΠ΄Π°Π»Π΅Π½Π½Ρ‹Π΅ сСрвСра, Π° ΡƒΠΆΠ΅ ΠΏΠΎΡ‚ΠΎΠΌ ΠΈΡΠΊΠ°Ρ‚ΡŒ объяснСниС, ΠΏΠΎΡ‡Π΅ΠΌΡƒ происходит ΠΈΠΌΠ΅Π½Π½ΠΎ Ρ‚Π°ΠΊ. ΠžΡ‡Π΅Π½ΡŒ ΠΌΠ°Π»ΠΎ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ ΠΏΠΎ этому ΠΏΠΎΠ²ΠΎΠ΄Ρƒ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡ‚ΠΈ Π² Π˜Π½Ρ‚Π΅Ρ€Π½Π΅Ρ‚Π΅. Π’Π°ΠΊ, Π² экспСримСнтах ΠΌΡ‹ ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠΈΠ»ΠΈ, Ρ‡Ρ‚ΠΎ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ ΠΏΠΎ фиксированной Π΄Π°Ρ‚Π΅ ΡƒΠ»Π΅Ρ‚Π°Π΅Ρ‚ Π½Π° ΡƒΠ΄Π°Π»Π΅Π½Π½Ρ‹ΠΉ сСрвСр Π½Π° ΡƒΡ€Π°, Π° Π²ΠΎΡ‚ ΠΊΠΎΠ³Π΄Π° ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ Π·Π°Π΄Π°Ρ‚ΡŒ Π΄Π°Ρ‚Ρƒ динамичСски, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, now() ΠΈΠ»ΠΈ CURRENT_DATE, Ρ‚Π°ΠΊΠΎΠ³ΠΎ Π½Π΅ происходит. Π’ нашСм ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅, ΠΌΡ‹ Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈ Ρ‚Π°ΠΊΠΎΠΉ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€, Ρ‡Ρ‚ΠΎΠ±Ρ‹ столбСц created_at содСрТал Π² сСбС Π΄Π°Π½Π½Ρ‹Π΅ Ρ€ΠΎΠ²Π½ΠΎ Π·Π° 1 мСсяц Π² ΠΏΡ€ΠΎΡˆΠ»ΠΎΠΌ (BETWEEN CURRENT_DATE β€” INTERVAL ‘7 month’ AND CURRENT_DATE β€” INTERVAL ‘6 month’). Π§Ρ‚ΠΎ ΠΆΠ΅ ΠΌΡ‹ прСдприняли Π² Π΄Π°Π½Π½ΠΎΠΌ случаС?

explain analyze verbose
SELECT count(1)
FROM fdw_schema.table 
WHERE is_active is True
AND created_dt >= (SELECT CURRENT_DATE::timestamptz - INTERVAL '7 month') 
AND created_dt <(SELECT CURRENT_DATE::timestamptz - INTERVAL '6 month')
AND meta->>'source' = 'test';

Aggregate  (cost=306875.17..306875.18 rows=1 width=8) (actual time=4789.114..4789.115 rows=1 loops=1)
  Output: count(1)
  InitPlan 1 (returns $0)
    ->  Result  (cost=0.00..0.02 rows=1 width=8) (actual time=0.007..0.008 rows=1 loops=1)
          Output: ((('now'::cstring)::date)::timestamp with time zone - '7 mons'::interval)
  InitPlan 2 (returns $1)
    ->  Result  (cost=0.00..0.02 rows=1 width=8) (actual time=0.002..0.002 rows=1 loops=1)
          Output: ((('now'::cstring)::date)::timestamp with time zone - '6 mons'::interval)
  ->  Foreign Scan on fdw_schema."table"  (cost=100.02..306874.86 rows=105 width=0) (actual time=23.475..4681.419 rows=1360025 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Filter: (("table".is_active IS TRUE) AND (("table".meta ->> 'source'::text) = 'test'::text))
        Rows Removed by Filter: 76934
        Remote SQL: SELECT is_active, meta FROM fdw_schema.table WHERE ((created_dt >= $1::timestamp with time zone)) AND ((created_dt < $2::timestamp with time zone))
Planning time: 0.703 ms
Execution time: 4789.379 ms

ΠœΡ‹ подсказали ΠΏΠ»Π°Π½ΠΈΡ€ΠΎΠ²Ρ‰ΠΈΠΊΡƒ Π·Π°Ρ€Π°Π½Π΅Π΅ Π²Ρ‹Ρ‡ΠΈΡΠ»ΠΈΡ‚ΡŒ Π΄Π°Ρ‚Ρƒ Π² подзапросС ΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ΡƒΠΆΠ΅ Π³ΠΎΡ‚ΠΎΠ²ΡƒΡŽ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ Π² Ρ„ΠΈΠ»ΡŒΡ‚Ρ€. И эта подсказка Π΄Π°Π»Π° Π½Π°ΠΌ прСкрасный Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚, запрос стал быстрСС ΠΏΠΎΡ‡Ρ‚ΠΈ Π² 6 Ρ€Π°Π·!

ΠžΠΏΡΡ‚ΡŒ ΠΆΠ΅, здСсь Π²Π°ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ Π²Π½ΠΈΠΌΠ°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌ: Ρ‚ΠΈΠΏ Π΄Π°Π½Π½Ρ‹Ρ… Π² подзапросС Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ Ρ‚Π°ΠΊΠΈΠΌ ΠΆΠ΅, Ρ‡Ρ‚ΠΎ ΠΈ Ρƒ поля, ΠΏΠΎ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌΡƒ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΡƒΠ΅ΠΌ, ΠΈΠ½Π°Ρ‡Π΅ ΠΏΠ»Π°Π½ΠΈΡ€ΠΎΠ²Ρ‰ΠΈΠΊ Ρ€Π΅ΡˆΠΈΡ‚, Ρ‡Ρ‚ΠΎ Ρ€Π°Π· Ρ‚ΠΈΠΏΡ‹ Ρ€Π°Π·Π½Ρ‹Π΅ ΠΈ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ сначала Π΄ΠΎΡΡ‚Π°Ρ‚ΡŒ всС Π΄Π°Π½Π½Ρ‹Π΅ ΠΈ ΡƒΠΆΠ΅ локально ΠΎΡ‚Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΠΎΠ²Π°Ρ‚ΡŒ.

Π’Π΅Ρ€Π½Π΅ΠΌ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ ΠΏΠΎ Π΄Π°Ρ‚Π΅ Π² исходноС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.

Freddy vs. Jsonb

Π’ ΠΎΠ±Ρ‰Π΅ΠΌ-Ρ‚ΠΎ Π±ΡƒΠ»Π΅Π²Ρ‹ поля ΠΈ Π΄Π°Ρ‚Ρ‹ ΡƒΠΆΠ΅ достаточно ускорили наш запрос, ΠΎΠ΄Π½Π°ΠΊΠΎ оставался Π΅Ρ‰Π΅ ΠΎΠ΄ΠΈΠ½ Ρ‚ΠΈΠΏ Π΄Π°Π½Π½Ρ‹Ρ…. Π‘ΠΈΡ‚Π²Π° с Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΠ΅ΠΉ ΠΏΠΎ Π½Π΅ΠΌΡƒ, чСстно говоря, Π΄ΠΎ сих ΠΏΠΎΡ€ Π½Π΅ ΠΎΠΊΠΎΠ½Ρ‡Π΅Π½Π°, хотя ΠΈ здСсь Π΅ΡΡ‚ΡŒ успСхи. Π˜Ρ‚Π°ΠΊ, Π²ΠΎΡ‚ ΠΊΠ°ΠΊ Ρƒ нас ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΎΡΡŒ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ ΠΏΠΎ jsonb полю Π½Π° ΡƒΠ΄Π°Π»Π΅Π½Π½Ρ‹ΠΉ сСрвСр.

explain analyze verbose
SELECT count(1)
FROM fdw_schema.table 
WHERE is_active is True
AND created_dt BETWEEN CURRENT_DATE - INTERVAL '7 month' 
AND CURRENT_DATE - INTERVAL '6 month'
AND meta @> '{"source":"test"}'::jsonb;

Aggregate  (cost=245463.60..245463.61 rows=1 width=8) (actual time=6727.589..6727.590 rows=1 loops=1)
  Output: count(1)
  ->  Foreign Scan on fdw_schema."table"  (cost=1100.00..245459.90 rows=1478 width=0) (actual time=16.213..6634.794 rows=1360025 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Filter: (("table".is_active IS TRUE) AND ("table".created_dt >= (('now'::cstring)::date - '7 mons'::interval)) AND ("table".created_dt <= ((('now'::cstring)::date)::timestamp with time zone - '6 mons'::interval)))
        Rows Removed by Filter: 619961
        Remote SQL: SELECT created_dt, is_active FROM fdw_schema.table WHERE ((meta @> '{"source": "test"}'::jsonb))
Planning time: 0.747 ms
Execution time: 6727.815 ms

ВмСсто ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΠ² Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΠΈ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ наличия ΠΎΠ΄Π½ΠΎΠ³ΠΎ jsonb Π² Π΄Ρ€ΡƒΠ³ΠΎΠΌ. 7 сСкунд вмСсто исходных 29. Пока это СдинствСнный ΡƒΡΠΏΠ΅ΡˆΠ½Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΠΎΠ² ΠΏΠΎ jsonb Π½Π° ΡƒΠ΄Π°Π»Π΅Π½Π½Ρ‹ΠΉ сСрвСр, Π½ΠΎ здСсь Π²Π°ΠΆΠ½ΠΎ ΡƒΡ‡Π΅ΡΡ‚ΡŒ ΠΎΠ΄Π½ΠΎ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΠ΅: ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Π²Π΅Ρ€ΡΠΈΡŽ Π±Π°Π·Ρ‹ 9.6, ΠΎΠ΄Π½Π°ΠΊΠΎ Π΄ΠΎ ΠΊΠΎΠ½Ρ†Π° апрСля ΠΏΠ»Π°Π½ΠΈΡ€ΡƒΠ΅ΠΌ Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ΡŒ послСдниС тСсты ΠΈ ΠΏΠ΅Ρ€Π΅Π΅Ρ…Π°Ρ‚ΡŒ Π½Π° 12 Π²Π΅Ρ€ΡΠΈΡŽ. Как обновимся, напишСм, ΠΊΠ°ΠΊ это повлияло, вСдь ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠ½ΠΎΠ³ΠΎ Π½Π°Π΄Π΅ΠΆΠ΄, достаточно ΠΌΠ½ΠΎΠ³ΠΎ: json_path, Π½ΠΎΠ²ΠΎΠ΅ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ CTE, push down (ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ с 10 вСрсии). ΠžΡ‡Π΅Π½ΡŒ хочСтся скорСС ΠΏΠΎΠΏΡ€ΠΎΠ±ΠΎΠ²Π°Ρ‚ΡŒ.

Finish him

ΠœΡ‹ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠ»ΠΈ, ΠΊΠ°ΠΊ ΠΊΠ°ΠΆΠ΄ΠΎΠ΅ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ влияСт Π½Π° ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ запроса ΠΏΠΎ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ. Π”Π°Π²Π°ΠΉΡ‚Π΅ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ посмотрим, Ρ‡Ρ‚ΠΎ Π±ΡƒΠ΄Π΅Ρ‚, ΠΊΠΎΠ³Π΄Π° всС Ρ‚Ρ€ΠΈ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π° Π±ΡƒΠ΄ΡƒΡ‚ написаны ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ.

explain analyze verbose
SELECT count(1)
FROM fdw_schema.table 
WHERE is_active = True
AND created_dt >= (SELECT CURRENT_DATE::timestamptz - INTERVAL '7 month') 
AND created_dt <(SELECT CURRENT_DATE::timestamptz - INTERVAL '6 month')
AND meta @> '{"source":"test"}'::jsonb;

Aggregate  (cost=322041.51..322041.52 rows=1 width=8) (actual time=2278.867..2278.867 rows=1 loops=1)
  Output: count(1)
  InitPlan 1 (returns $0)
    ->  Result  (cost=0.00..0.02 rows=1 width=8) (actual time=0.010..0.010 rows=1 loops=1)
          Output: ((('now'::cstring)::date)::timestamp with time zone - '7 mons'::interval)
  InitPlan 2 (returns $1)
    ->  Result  (cost=0.00..0.02 rows=1 width=8) (actual time=0.003..0.003 rows=1 loops=1)
          Output: ((('now'::cstring)::date)::timestamp with time zone - '6 mons'::interval)
  ->  Foreign Scan on fdw_schema."table"  (cost=100.02..322041.41 rows=25 width=0) (actual time=8.597..2153.809 rows=1360025 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Remote SQL: SELECT NULL FROM fdw_schema.table WHERE (is_active) AND ((created_dt >= $1::timestamp with time zone)) AND ((created_dt < $2::timestamp with time zone)) AND ((meta @> '{"source": "test"}'::jsonb))
Planning time: 0.820 ms
Execution time: 2279.087 ms

Π”Π°, запрос выглядит слоТнСС, это вынуТдСнная ΠΏΠ»Π°Ρ‚Π°, Π½ΠΎ ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ выполнСния составляСт 2 сСкунды, Ρ‡Ρ‚ΠΎ Π±ΠΎΠ»Π΅Π΅ Ρ‡Π΅ΠΌ Π² 10 Ρ€Π°Π· быстрСС! И это ΠΌΡ‹ Π³ΠΎΠ²ΠΎΡ€ΠΈΠΌ ΠΎ простом запросС ΠΊ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Π½Π΅Π±ΠΎΠ»ΡŒΡˆΠΎΠΌΡƒ Π½Π°Π±ΠΎΡ€Ρƒ Π΄Π°Π½Π½Ρ‹Ρ…. На Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Ρ… запросах ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Π»ΠΈ прирост Π΄ΠΎ Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… сотСн Ρ€Π°Π·.

ПодвСдСм ΠΈΡ‚ΠΎΠ³ΠΈ: Ссли Π²Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚Π΅ PostgreSQL с FDW, всСгда провСряйтС, всС Π»ΠΈ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Ρ‹ ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡŽΡ‚ΡΡ Π½Π° ΡƒΠ΄Π°Π»Π΅Π½Π½Ρ‹ΠΉ сСрвСр, ΠΈ Π±ΡƒΠ΄Π΅Ρ‚ Π²Π°ΠΌ ΡΡ‡Π°ΡΡ‚ΡŒΠ΅β€¦ По ΠΊΡ€Π°ΠΉΠ½Π΅ΠΉ ΠΌΠ΅Ρ€Π΅, ΠΏΠΎΠΊΠ° Π²Ρ‹ Π½Π΅ Π΄ΠΎΠΉΠ΄Π΅Ρ‚Π΅ Π΄ΠΎ Π΄ΠΆΠΎΠΉΠ½ΠΎΠ² ΠΌΠ΅ΠΆΠ΄Ρƒ Ρ‚Π°Π±Π»ΠΈΡ†Π°ΠΌΠΈ с Ρ€Π°Π·Π½Ρ‹Ρ… сСрвСров. Но это ΡƒΠΆΠ΅ история для Π΅Ρ‰Π΅ ΠΎΠ΄Π½ΠΎΠΉ ΡΡ‚Π°Ρ‚ΡŒΠΈ.

Бпасибо Π·Π° Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅! Π‘ΡƒΠ΄Ρƒ Ρ€Π°Π΄ ΡƒΡΠ»Ρ‹ΡˆΠ°Ρ‚ΡŒ вопросы, ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΈ, Π° Ρ‚Π°ΠΊΠΆΠ΅ истории ΠΎ вашСм ΠΎΠΏΡ‹Ρ‚Π΅ Π² коммСнтариях.

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

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ