Pertempuran MERGE. Kronik dengan kesimpulan dan moralitas

Beberapa minggu sebelum festival komit yang penting - yang terakhir sebelum feature freeze versi PostgreSQL 11 - buletin peretas , mengompresi chipset dalam paket kiri, menyaksikan film thriller MERGE . Sutradara thriller dan CEO 2ndQuadrant, Simon Riggs , mencoba mendorong tambalan yang mengimplementasikan sintaksis perintah MERGE dengan ketekunan dan kecerdikan yang mengesankan. Riggs telah menjadi komedian sejak 2009, dan dengan status seorang komedian Anda dapat menyetujui tambalan sendiri. Dia ditentang oleh komite dan veteran PostgreSQL yang tidak kalah dihormati. Gairah menggebu-gebu jelas dan tersirat, itu bahkan tidak datang untuk menghina langsung - fakta mengejutkan bagi pelanggan tetap di banyak forum domestik. Namun, beberapa ketegangan tetap sejauh ini ketika pertanyaan diselesaikan, dan tidak ada yang perlu diperdebatkan.

Tapi nafsu adalah nafsu (mereka akan dibahas lebih lanjut), dan saya ingin memilah esensi dari masalah yang sepenuhnya dibuat-buat ini.


GABUNG di luar


Jika benar-benar menyederhanakan, maka masalahnya adalah ini: kami memiliki 2 tabel dengan bidang yang sama dan data yang berbeda. Asumsikan nama dan umur. Kita perlu menggabungkan mereka menjadi satu. Tetapi akan perlu untuk memutuskan apa yang harus dilakukan dengan kepribadian yang ada di kedua tabel. Kemungkinan besar kita akan menginginkan semua yang ada di tabel akhir, dan untuk memperbarui informasi ke individu yang cocok. Jelas bahwa bahkan dalam pengaturan ini, ini adalah tugas yang sangat umum. Ini dapat diselesaikan tanpa MERGE , membuat permintaan yang kompleks, Anda dapat menggunakan pemicu dan sebagainya. Tapi itu tidak nyaman. Namun, versi non-kanonik dari MERGE, yang disebut UPSERT (UPdate + inSERT), menyelesaikan masalah ini.

Operator MERGE berada dalam standar SQL-2003 dan sudah dalam kejayaannya dalam SQL-2008. Ini diimplementasikan dalam Oracle, DB2 dan MS SQL, yang berarti kurangnya MERGE akan mengecewakan mereka yang mempertimbangkan untuk beralih dari DBMS ke PostgreSQL. Keinginan kerinduan Simon Riggs secepat mungkin, sudah ada di PostgreSQL 11, didorong oleh keinginan pelanggan 2ndQuadrant, dan bukan oleh ambisi atau pertengkaran.

Faktanya, MERGE memiliki kemampuan yang kaya, data tidak harus diambil dari tabel, terutama dari yang serupa dalam struktur.

Sintaks perintahnya adalah sebagai berikut:

  MERGE INTO tablename USING table_reference ON (condition) WHEN MATCHED THEN UPDATE SET column1 = value1 [, column2 = value2 ...] WHEN NOT MATCHED THEN INSERT (column1 [, column2 ...]) VALUES (value1 [, value2 ...]); 

Namun, Anda dapat menyukai ini:

 MERGE [hint] INTO [schema .] {table | view} [table_alias] USING { subquery | [schema .] { table | view}} [table_alias] ON ( condition ) [ merge_update_clause ] [ merge_insert_clause ] [ error_logging_clause ] ; 

Sintaks ini diimplementasikan dalam Oracle. Dalam kata-kata, kemudian MERGE melakukan tindakan yang mengubah catatan dalam tabel target target_table_name menggunakan data_source dalam perintah SQL tunggal, yang dapat, sesuai dengan kondisi, lakukan INSERT, UPDATE atau DELETE sehubungan dengan catatan dalam target_table_name. Dalam hal ini, target_table_name dapat berupa tampilan, dan data_source dapat berupa serangkaian tabel atau tampilan, hasil dari subquery .

Pertama, MERGE melakukan left outer join pada data_source dengan target_table_name , menyarankan 0 atau lebih catatan perubahan kandidat; WHEN klausa dihitung dalam urutan yang ditentukan; segera setelah kondisi terpenuhi, tindakan yang sesuai dilakukan. Kata kunci WHEN [NOT] MATCH THEN tidak terlalu umum dalam SQL , jadi kami mengingatkan Anda bahwa ini adalah konstruk kontrol seperti if-else dalam bahasa lain. MERGE bertindak dengan cara yang sama seperti UPDATE, INSERT atau DELETE sehubungan dengan target_table_name , hanya sintaks seluruh perintah yang berbeda.

Klausa dengan ON harus membuat koneksi pada semua kolom kunci utama atau, jika kolom lain ditentukan, maka beberapa indeks unik harus digunakan sehingga kondisi [NOT] MATCHED segera menentukan tindakan untuk catatan kandidat untuk mengecualikan interaksi dengan transaksi lainnya.

Perintah deterministik MERGE : Anda tidak dapat memperbarui catatan yang sama beberapa kali dalam perintah MERGE yang sama.
Contoh:

 MERGE CustomerAccount CA USING RecentTransactions T ON T.CustomerId = CA.CustomerId WHEN MATCHED THEN UPDATE SET Balance = Balance + TransactionValue WHEN NOT MATCHED THEN INSERT (CustomerId, Balance) VALUES (T.CustomerId, T.TransactionValue); 

atau dengan subquery:

 MERGE INTO bonuses D USING (SELECT employee_id, salary, department_id FROM employees WHERE department_id = 80) S ON (D.employee_id = S.employee_id) WHEN MATCHED THEN UPDATE SET D.bonus = D.bonus + S.salary*.01 DELETE WHERE (S.salary > 8000) WHEN NOT MATCHED THEN INSERT (D.employee_id, D.bonus) VALUES (S.employee_id, S.salary*.01) WHERE (S.salary <= 8000); 

Di IBM DB2, sintaks akan bekerja juga. Seperti yang mereka katakan , "di bawah tenda" ini akan dilakukan mirip dengan konstruksi UPDATE FROM .
Sejak 2008, MS SQL juga memiliki MERGE .

Tetapi bahkan di balik sintaks standar tunggal, masalah memilih dari sejumlah besar mekanisme dan metode implementasi dimulai. Tim harus bekerja pada tingkat isolasi transaksi yang berbeda, dengan algoritme penguncian yang berbeda, dengan fokus pada mode operasi yang sangat kompetitif atau tidak-jadi-begitu. Dan, seperti yang Anda duga, untuk mengimplementasikan logika yang rumit ini, Anda perlu menyentuh banyak komponen DBMS.

UPSERT, pseudo-MERGE


Jelas bahwa pengembang DBMS mencari solusi kompromi, menolak untuk benar-benar mereproduksi sintaks standar. Kelebihan dari pendekatan ini adalah kebebasan. Anda dapat menggunakan mekanisme yang organik untuk DBMS tertentu, Anda dapat mengoptimalkan implementasi untuk tugas-tugas yang Anda anggap paling relevan bagi pengguna Anda.

Misalnya, di MySQL ada perintah REPLACE yang berfungsi sebagai INSERT , tetapi jika baris baru dan lama memiliki nilai yang sama dalam indeks PRIMARY KEY atau indeks UNIQUE , maka baris lama terbunuh sebelum yang baru dimasukkan. Tetapi ada juga INSERT ... ON DUPLICATE KEY UPDATE mana INSERT dan UPDATE terjadi (bukan DELETE dalam REPLACE ). Ini adalah UPSERT . Dan ada INSERT IGNORE , yang tidak melakukan penyisipan, tanpa melemparkan kesalahan (tetapi peringatan) di bawah batasan tertentu pada tabel target.

Kronik PG MERGE


Di komunitas PostgreSQL, pembicaraan tentang MERGE dimulai pada 2005 ketika Jaime Casanova bertanya apakah ada orang di komunitas yang mulai mengembangkan MERGE . Peter Eisentraut menyarankan mendiskusikan apakah PostgreSQL harus mengembangkan salah satu opsi MERGE: mirip dengan implementasi MySQL, atau lebih baik untuk mengarahkan upaya ke versi ringan fungsional dari tipe MERGE dari Oracle. Namun, apakah layak untuk melakukan upaya ke arah ini?

Di tengah diskusi singkat, protagonis dari cerita ini Simon Riggs muncul dengan kata-kata:
MERGE berguna baik untuk sistem OLTP dan untuk DW (Data Warehouse - data warehouse, yaitu aplikasi analitis di mana pertanyaan kompleks, tetapi lingkungan yang tidak terlalu kompetitif dan data jarang diperbarui, dan jika diperbarui, biasanya dalam potongan besar. <...> Kita dapat mengimplementasikan MERGE sebagai varian dari COPY FROM, itu akan sangat keren.

Semua orang setuju: ya, keren. Lebih tepatnya, hampir semuanya: Stephen Frost : Saya pikir saya bukan satu-satunya yang mengatakan bahwa saya memerlukan standar MERGE yang lengkap dan patuh.

Bruce Momjian memiliki proposal yang berbeda dan lebih pragmatis: bagi saya tampaknya kita perlu mengimplementasikan beberapa opsi yang dapat diimplementasikan di MERGE , dan sisanya kami akan memberikan kesalahan (dan dalam kasus-kasus di mana akan diperlukan untuk memblokir seluruh tabel). Dan setelah kami mendapat umpan balik dari pengguna dan kami akan memikirkan apa yang harus dilakukan selanjutnya.

Namun sejauh ini tidak ada yang terjadi.

Esnya sudah pecah


Pada tahun 2008, Simon Riggs sekali lagi mendesak untuk berurusan dengan MERGE - yang mana dari cara untuk memilih (saat itu versi baru MERGE dalam standar SQL-2008, yang masih konsep, sudah muncul). Dia melukis secara rinci saat ini implementasi Oracle, IBM dan MS SQL dan sintaksis alternatif dari MySQL dan Teradata saat itu. Dan sedikit kemudian dia sudah menyebutkan awal pekerjaan di 2ndQuadrant ke arah ini.

Peter Eisentraut menulis di blognya : Tentu saja, Riggs adalah salah satu spesialis yang paling memenuhi syarat, ia dapat memimpin pekerjaan pada implementasi MERGE.

Tetapi inilah giliran pertama yang tidak terduga: seorang siswa terlibat dalam masalah - seorang peserta dalam pengembangan program GSoC , yaitu, Google Summer of Code. Namanya Boxuan Bxzhai - Saya tidak berani menuliskan nama belakang. Segera dia menulis bahwa pekerjaannya hampir selesai.

Tetapi hampir tidak masuk hitungan. Greg Smith dari 2ndQuadrant (mis. Simon Riggs ally) menulis:
Jadi, kami memiliki tambalan dalam kode yang setengah lusin masalah serius yang belum terselesaikan. Saya diam tentang hal-hal kecil. Masalahnya terlalu dalam untuk menyelesaikan kode untuk commitfest. Sementara itu, tidak ada yang terdengar dari Boxuan untuk waktu yang lama. Kita bisa membantunya, tetapi di mana dia? Siapa yang tahu?

Diskusi tentang jalur implementasi kembali berkobar di tahun 2014 , tetapi sekali lagi tidak ada yang terjadi: tidak ada kode.

Akhirnya, pada awal 2017, Simon Riggs menulis:
Saya sedang mengerjakan kode untuk mengkomit MERGE ke PostgreSQL versi 11 . Kami menggunakan mekanisme yang sama yang mendasari INSERT ON CONFLICT sudah berfungsi, sehingga tidak ada perubahan infrastruktur yang diperlukan, pada dasarnya hanya menerapkan sintaksis di atas apa yang tersedia. Tapi saya menulis kode saya dari awal, saya tidak menggunakan perkembangan sebelumnya.

Kita berbicara tentang Peter Geoghegan ( VMware ) yang diimplementasikan pada saat itu sudah dalam 9,5 alternatif sintaks INSERT .. ON CONFLICT UPDATE , berbeda dari standar SQL, tetapi masih terkait dengan MERGE dan REPLACE di MySQL.

Pada awalnya, karya Simon disambut dengan seru dari karya Nice! Namun, Robert Haas , meskipun mendukung, memperingatkan kemungkinan anomali serialisasi. Seperti, untuk berurusan dengan INSERT .. ON CONFLICT UPDATE , tanpa MERGE pada dasarnya, entah bagaimana lebih tenang.

PostgreSQL UPSERT penulis UPSERT sendiri:
Saya tidak akan mencampur kode ON CONFLICT DO UPDATE dan MERGE . <...> Untuk memuat potongan besar data ( bulk load ) saya akan, misalnya, menggunakan algoritma merge join . <...> Secara umum, keunggulan MERGE akan terkait dengan fakta bahwa koneksi normal akan bekerja di sana dengan cara yang biasa: nested loop, hash, merge . Dan di INSERT โ€ฆ ON CONFLICT tidak ada gabungan sama sekali.

Haas: Seperti Peter, saya pikir jika dilakukan dengan cara ini, maka kunci yang kuat ketika menjalankan permintaan DML terlihat begitu-begitu. Tidak mungkin ada orang yang senang bahwa hanya satu orang yang dapat bekerja dengan MERGE pada satu waktu.

Bagi mereka yang penasaran: Geigan mem-parsing kehalusan dan perbedaan besar antara MERGE dan MERGE sini dan di sini (kami menyimpan korespondensi yang diarsipkan dari PostgreSQL di situs web kami).

Simon menolak. Ia mengimbau Sejarah Terbaru. Seperti, tentang perpisahan mereka juga mengatakan "sintaks baru, tidak lebih." Namun ternyata hal itu menjadi hal yang sangat berguna. Tetapi saya tidak mengusulkan untuk segera merealisasikan semua yang ada dalam MERGE. Kami akan melakukan hal yang sama dengan mempartisi - kami membagi pengembangan menjadi beberapa fase.

Dan satu argumen lagi, menurut saya sangat meyakinkan: Bagus. Tapi mari kita pilih. Saya menyarankan opsi praktis. 10 tahun akan segera datang dari upaya serius pertama untuk mengembangkan MERGE . Bukankah sudah waktunya untuk mulai melakukan sesuatu, untuk mendapatkan beberapa solusi yang bermanfaat, alih-alih menunggu 10 tahun Solusi Sempurna? Dengan asumsi itu ada sama sekali.

Akhirnya, tambalan tiba di komunitas. Tanggal berapa? Tolong bayangkan. Tidak, mereka tidak menebak: Simon mengirimnya pada 30 Desember 2017. Dan menetapkan bahwa ini adalah patch WIP, yaitu, Work in Progress - patch in work.

Simon, Januari:
Patch selesai tanpa bug khusus. 1200 baris kode plus tes dan dokumentasi. Saya akan mengkomitnya ke commitfest ini, dan kami akan menyelesaikan RLS (Row Level Security - perlindungan di tingkat perekaman) dan dukungan partisi nanti.

Komite dari kasta


Di sini kita harus mengambil langkah ke samping dan menjelaskan peran komisaris di masyarakat. Fungsi komisaris, yaitu, orang yang diberdayakan untuk menerima tambalan di versi berikutnya, telah berubah secara historis. Sekali waktu, ketika ada beberapa pengembang, hak untuk melakukan didistribusikan dengan murah hati. Sebagai contoh, Julian Assange yang terkenal (dalam bidang yang sama sekali berbeda) menerima gelar komandan, menjadi penulis hanya enam tambalan. Sekarang tidak mudah untuk menjadi komisaris, tidak ada pemula dalam daftar beberapa lusin orang. Boyus Momdjan ( EnterpriseDB ) memiliki 13.363 komit, Tom Lane (Tom Lane, Crunchy Data ) 13127, Robert Haas ( EnterpriseDB ) - 2074. Omong-omong, satu - satunya committer dari Rusia adalah Fedor Sigaev ( Postgres Professional ) dengan 383 komitnya . Simon Riggs sendiri memiliki 449. Saya ulangi: dia, sebagai seorang komisaris, memiliki cukup wewenang untuk mengambil dan melakukan perbaikan - dia dan karyawannya. Hal lain adalah bahwa hampir tidak ada gunanya melakukan hal ini, terus terang mengabaikan pendapat komite-komite terkemuka lainnya. Mereka juga dapat menghilangkan status komisaris, tetapi setidaknya mereka akan revert patch kembali.

Fraktur dalam pertempuran


Tentu saja, di patch "putus asa", dibuat, secara umum, dengan tergesa-gesa, mereka menemukan kesalahan baru. Versi baru merespons.

Pada akhir Januari, muncul karakter baru: pengembang 2ndQuadrant Pavan (namanya semua orang dengan nama; sepenuhnya Pavan Deolasee). Sekarang masyarakat berhadapan dengan tandem: Pavan mengirimkan versi baru dan terima kasih atas kritiknya, dan Simon menghancurkan mereka dengan tekanan pemasaran yang luar biasa.

Haas: Saya rasa tidak perlu mengambil keputusan sepihak untuk mengecualikan fitur yang bekerja di mana-mana. Jika kami setuju bahwa beberapa fitur tidak akan disertakan dalam tambalan ini - ini adalah satu hal. Dan sangat berbeda bahwa dalam komentar pada kesempatan ini semua orang menyatakan ketidaksetujuan. Dan kami sebenarnya tidak mendengar alasan mengapa fitur ini harus dikecualikan.

Logikanya disajikan sebagai berikut:

  • a priori, ada masalah serius karena mereka tidak bisa tidak berada dalam perkembangan dalam gaya "serangan kavaleri."
  • Dukungan bahkan untuk fitur-fitur penting seperti partisi baru di versi 10-11, CTE (Common Table Expressions = WITH queries) atau RLS (Row Level Security) dapat diselesaikan bahkan setelah patch diterima dalam versi saat ini, tetapi hanya jika arsitektur yang diusulkan cocok untuk membangun di atas fungsi yang diinginkannya.

Peter Geigan kedua merumuskan ini:
Biasanya saya memperhatikan dukungan berbagai fungsi, karena jika ya, itu memperkuat kepercayaan umum bahwa desain dibuat sebagaimana mestinya . Dan jika masalah tersebut disebabkan oleh dukungan dengan ekspresi [yaitu, CTE ], maka saya mendapatkan ide bahwa arsitektur yang mendasarinya sedemikian rupa sehingga akan menyebabkan masalah di sana-sini.

Sementara itu, jam X (panitia terakhir) semakin dekat, dan awan di atas MERGE berkumpul. Bukan karena para pendiri pendiri secara khusus mencari masalah serius dalam arsitektur tambalan yang dibuat oleh Simon dan kemudian Pavan. Saya tidak perlu mencari masalah, mereka rela membuka diri.

Pengunduran diri sudah dekat


Plotnya semakin cepat. Meskipun sikap keren komite lain terhadap usahanya, pada tanggal 2 April, Simon memutuskan untuk melakukan Komando berikut SQL: patch 2016 , menambahkan file, Depesz (Hubert Lubachevsky) berhasil mengumumkannya di blog-nya, tetapi pada hari yang sama Simon mengembalikan semuanya karena kesalahan.

Hari berikutnya, komit kembali dengan menambahkan WITH dukungan.

Sebagai tanggapan, tuduhan itu benar-benar serius. Andres Freund ( EnterpriseDB ) menulis:
Arsitektur untuk MERGE di parser dan pelaksana tidak membuat saya terkesan. Membuat sambungan tersembunyi selama analisis parsing adalah ide yang sangat buruk. Struktur pelaksana ini harus benar-benar diubah.

Tom Lane:
Desain pohon parsing lemah.



Anda membebani fungsi InsertStmt , ia melanjutkan, itu tidak melakukan INSERT sama sekali, tetapi secara acak memiliki bidang yang sama dengan yang asli. Dan tidak semua, tetapi beberapa. Ini buruk, itu menyebabkan kebingungan.

Mari tambahkan pengamatan Fedor Sigayev :
Di parser, node INSERT terkait MERGE muncul, digantung dengan sekelompok bidang tambahan. Jika Anda melihat rencana pelaksanaan dalam ANALIZE , Anda tidak akan segera mengerti apakah Anda berurusan dengan INSERT biasa atau dengan MERGE : untuk memahami, Anda perlu melihat bidang tambahan.


Simon, dengan tenang: OK, kita akan mengubahnya dan mengirim file baru besok .
Haas: Saya setuju dengan Peter. Pilihan arsitektur tidak berhasil.

Simon tidak menyerah. 6 April, dalam menanggapi kritik terhadap Tom Lane, melakukan tambalan baru sebagaimana telah diubah dalam pengurai.

Negosiasi dan penyerahan


Bruce Momjan 6 April :
Saya ingin mencatat bahwa orang tidak meminta Anda untuk bekerja keras untuk segera memperbaiki sesuatu. Mereka meminta Anda untuk menarik tambalan. Anda dapat, tentu saja, bekerja keras, berharap mereka akan berubah pikiran, tetapi - sekali lagi - mereka tidak menanyakan hal itu kepada Anda.

Simon: Jika Tom [Lane] dan Andres [Freund] selama beberapa hari masih merasa bahwa ketakutan mereka belum hilang , saya akan dengan senang hati mengembalikan tambalan tanpa basa-basi lagi.

Tom Lane: Saya masih memilih tambalan untuk dibatalkan. Bahkan jika dia sempurna sekarang, sekarang orang tidak punya waktu untuk diyakinkan tentang ini - ke tenggorokan masalah mendesak lainnya.

Itu saja.

Simon berkata OK, dan pertempuran di MERGE berakhir. Semua tambalan telah dipompa kembali, topik telah dipindahkan ke commitfest berikutnya dengan status "Menunggu penyelesaian penulis". Para peserta dalam pertunjukan berdamai.


Namun, dilihat dari korespondensi beberapa minggu terakhir, beberapa ketegangan tampaknya tetap ada.

Moralitas yang Dijanjikan


  • Untungnya, komunitas PostgreSQL memiliki mekanisme alami dan formal untuk (hampir) penyaringan upaya-upaya untuk solusi yang belum matang. Bahkan jika mereka dipukul oleh pengembang yang dihormati di pangkat kepala perusahaan, yang kontribusinya terhadap pengembangan PostgreSQL sangat besar. Dan pelanggan yang kurang fungsional mendorong untuk berinvestasi.
  • Sayangnya, komunitasnya sering warung. Ia bersifat inersia dalam mengadopsi perkembangan yang bahkan jelas relevan. Terkadang perfeksionisme yang irasional dimasukkan. Pengalaman Postgres Professional, tempat saya bekerja, menegaskan hal ini. Kami menekan patch besar termasuk indeks INCLUDE selama 3 tahun. Serangkaian tambalan yang berguna untuk bekerja dengan JSON / JSONB masih menunggu. Ungkapan "berikan pengembangan Anda ke komunitas" tidak benar - benar berarti memberi, tetapi meninju : tamu disambut dengan tangan terbuka dan dikawal ke karantina.

PS: Penafian dari penulis : kami hanya ingin menunjukkan sepotong kehidupan komunitas. Semua nama yang cocok adalah acak :)
PPS: Samurai Natalia Levshina .

Source: https://habr.com/ru/post/id412605/


All Articles