Database menulis dan membaca balancing

gambar

Dalam artikel sebelumnya , saya menjelaskan konsep dan implementasi database yang dibangun berdasarkan fungsi, bukan tabel dan bidang seperti dalam database relasional. Ini memberi banyak contoh yang menunjukkan keuntungan dari pendekatan ini dibandingkan klasik. Banyak yang menemukan mereka tidak cukup meyakinkan.

Dalam artikel ini saya akan menunjukkan bagaimana konsep ini memungkinkan Anda untuk dengan cepat dan nyaman menyeimbangkan penulisan dan membaca ke database tanpa ada perubahan dalam logika kerja. Mereka mencoba menerapkan fungsi yang serupa dalam DBMS komersial modern (khususnya, Oracle dan Microsoft SQL Server). Di akhir artikel, saya akan menunjukkan apa yang terjadi pada mereka, secara halus, tidak terlalu.

Deskripsi


Seperti sebelumnya, untuk pemahaman yang lebih baik, saya akan memulai deskripsi dengan contoh-contoh. Misalkan kita perlu menerapkan logika yang akan mengembalikan daftar departemen dengan jumlah karyawan di dalamnya dan total gaji mereka.

Dalam database fungsional, akan terlihat seperti ini:
CLASS Department '';
name '' = DATA STRING [ 100 ] (Department);

CLASS Employee '';
department '' = DATA Department (Employee);
salary '' = DATA NUMERIC [ 10 , 2 ] (Employee);

countEmployees '- ' (Department d) =
GROUP SUM 1 IF department(Employee e) = d;
salarySum ' ' (Department d) =
GROUP SUM salary(Employee e) IF department(e) = d;

SELECT name(Department d), countEmployees(d), salarySum(d);
Kompleksitas menjalankan kueri ini dalam DBMS apa pun akan setara dengan O (jumlah karyawan) , karena untuk perhitungan ini Anda perlu memindai seluruh tabel karyawan, dan kemudian mengelompokkannya menurut departemen. Akan ada juga penambahan kecil (kami percaya bahwa ada lebih banyak karyawan daripada departemen) tergantung pada rencana yang dipilih O (jumlah log karyawan) atau O (jumlah departemen) untuk pengelompokan dan sebagainya.

Jelas bahwa overhead untuk eksekusi dapat berbeda dalam DBMS yang berbeda, tetapi kompleksitasnya tidak akan berubah dengan cara apa pun.

Dalam implementasi yang diusulkan, DBMS fungsional akan membentuk satu subquery, yang akan menghitung nilai yang diperlukan untuk departemen, dan kemudian membuat GABUNG dengan tabel departemen untuk mendapatkan nama. Namun, untuk setiap fungsi, ketika mendeklarasikan, dimungkinkan untuk menentukan marker MATERIALISASI khusus. Sistem akan secara otomatis membuat bidang yang sesuai untuk setiap fungsi tersebut. Ketika nilai fungsi berubah, nilai bidang akan berubah dalam transaksi yang sama. Saat mengakses fungsi ini, banding akan dilakukan ke bidang terhitung.

Secara khusus, jika Anda menempatkan MATERIALISASI untuk fungsi-fungsi yang dihitung Karyawan dan gaji , maka dalam tabel dengan daftar departemen, dua bidang ditambahkan di mana jumlah karyawan dan total gaji mereka akan disimpan. Dengan perubahan apa pun pada karyawan, gaji atau afiliasi mereka dengan departemen, sistem akan secara otomatis mengubah nilai-nilai bidang ini. Kueri di atas akan mulai mengakses bidang ini secara langsung dan akan dieksekusi untuk O (jumlah departemen) .

Apa batasannya? Hanya satu hal: fungsi seperti itu harus memiliki jumlah nilai input yang terbatas yang nilainya didefinisikan. Jika tidak, tidak mungkin untuk membangun tabel yang menyimpan semua nilainya, karena tidak mungkin ada tabel dengan jumlah baris yang tak terbatas.

Contoh:
employeesCount ' > N' (Department d, NUMERIC [ 10 , 2 ] N) =
GROUP SUM salary(Employee e) IF department(e) = d AND salary(e) > N;
Fungsi ini didefinisikan untuk jumlah nilai tak terbatas dari angka N (misalnya, nilai negatif apa pun cocok). Oleh karena itu, tidak dapat dimasukkan MATERIALISASI. Dengan demikian, ini adalah batasan logis dan bukan teknis (yaitu, bukan karena kami tidak dapat mengimplementasikan ini). Kalau tidak, tidak ada batasan. Anda dapat menggunakan pengelompokan, pengurutan, DAN dan ATAU, PARTISI, rekursi, dll.

Misalnya, dalam tugas 2.2 artikel sebelumnya, Anda dapat menggunakan MATERIALISASI pada kedua fungsi:
bought '' (Customer c, Product p, INTEGER y) =
GROUP SUM sum(Detail d) IF
customer(order(d)) = c AND
product(d) = p AND
extractYear(date(order(d))) = y MATERIALIZED ;
rating '' (Customer c, Product p, INTEGER y) =
PARTITION SUM 1 ORDER DESC bought(c, p, y), p BY c, y MATERIALIZED ;
SELECT contactName(Customer c), name(Product p) WHERE rating(c, p, 1997 ) < 3 ;
Sistem itu sendiri akan membuat satu tabel dengan kunci tipe Pelanggan , Produk dan INTEGER , menambahkan dua bidang ke dalamnya dan akan memperbarui nilai bidang di dalamnya dengan perubahan apa pun. Setelah panggilan lebih lanjut ke fungsi-fungsi ini, mereka tidak akan dihitung, tetapi nilai-nilai dari bidang yang sesuai akan dibaca.

Menggunakan mekanisme ini, Anda bisa, misalnya, menyingkirkan rekursi (CTE) dalam kueri. Secara khusus, pertimbangkan grup yang membuat pohon menggunakan hubungan anak / orang tua (setiap grup memiliki tautan ke orang tuanya):
parent = DATA Group (Group);
Dalam database fungsional, logika rekursi dapat didefinisikan sebagai berikut:
level (Group child, Group parent) = RECURSION 1l IF child IS Group AND parent == child
STEP 2l IF parent == parent($parent);
isParent (Group child, Group parent) = TRUE IF level(child, parent) MATERIALIZED ;
Karena MATERIALIZED ditempelkan untuk fungsi isParent , sebuah tabel dengan dua kunci (grup) akan dibuat untuk itu, di mana bidang isParent akan benar hanya jika kunci pertama adalah turunan dari yang kedua. Jumlah entri dalam tabel ini akan sama dengan jumlah grup dikalikan kedalaman rata-rata pohon. Jika perlu, misalnya, untuk menghitung jumlah keturunan kelompok tertentu, maka Anda dapat mengakses fungsi ini:
childrenCount (Group g) = GROUP SUM 1 IF isParent(Group child, g);
Tidak akan ada CTE dalam kueri SQL. Sebagai gantinya, akan ada GROUP BY sederhana.

Dengan menggunakan mekanisme ini, Anda juga dapat dengan mudah mendenormalkan basis data jika perlu:
CLASS Order '' ;
date '' = DATA DATE (Order);

CLASS OrderDetail ' ' ;
order '' = DATA Order (OrderDetail);
date '' (OrderDetail d) = date(order(d)) MATERIALIZED INDEXED ;
Saat Anda memanggil fungsi tanggal untuk baris pesanan, bacaan akan dari tabel dengan baris urutan bidang yang ada indeksnya. Saat mengubah tanggal pesanan, sistem itu sendiri secara otomatis akan menghitung ulang tanggal yang dinon-denalkan di baris.

Manfaatnya


Mengapa seluruh mekanisme ini dibutuhkan? Dalam DBMS klasik, tanpa menulis ulang kueri, pengembang atau DBA hanya dapat mengubah indeks, menentukan statistik, dan memberi tahu perencana kueri bagaimana cara mengeksekusinya (apalagi, HINT hanya tersedia dalam DBMS komersial). Tidak peduli seberapa keras mereka berusaha, mereka tidak akan dapat memenuhi permintaan pertama dalam artikel untuk O (jumlah departemen) tanpa mengubah permintaan dan menambah pemicu. Dalam skema yang diusulkan, pada tahap pengembangan, Anda tidak perlu memikirkan struktur penyimpanan data dan agregasi mana yang akan digunakan. Semua ini dapat dengan mudah diubah dengan cepat, langsung beroperasi.

Dalam praktiknya, ini adalah sebagai berikut. Beberapa orang mengembangkan logika secara langsung berdasarkan tugas. Mereka tidak berpengalaman dalam algoritme dan kompleksitasnya, atau dalam rencana pelaksanaan, atau dalam jenis join'ov, atau dalam komponen teknis lainnya. Orang-orang ini lebih banyak analis bisnis daripada pengembang. Kemudian, semuanya masuk ke pengujian atau operasi. Log kueri panjang diaktifkan. Ketika permintaan panjang terdeteksi, maka orang lain (lebih teknis - pada kenyataannya DBA) memutuskan untuk memasukkan MATERIALISASI pada beberapa fungsi perantara. Dengan demikian, pencatatan sedikit melambat (karena memperbarui bidang tambahan dalam transaksi diperlukan). Namun, tidak hanya permintaan ini dipercepat secara signifikan, tetapi juga semua orang lain yang menggunakan fungsi ini. Pada saat yang sama, membuat keputusan tentang fungsi tertentu mana yang akan terwujud relatif sederhana. Dua parameter utama: jumlah nilai input yang mungkin (persis berapa banyak rekaman akan berada di tabel yang sesuai), dan seberapa sering digunakan dalam fungsi lain.

Analog


DBMS komersial modern memiliki mekanisme yang serupa: PANDANGAN MATERIALISASI dengan FAST REFRESH (Oracle) dan INDEXED VIEW (Microsoft SQL Server). Dalam PostgreSQL, MATERIALIZED VIEW tidak dapat memperbarui dalam transaksi, tetapi hanya berdasarkan permintaan (dan bahkan dengan batasan yang sangat ketat), jadi kami tidak mempertimbangkannya. Tetapi mereka memiliki beberapa masalah, yang sangat membatasi penggunaannya.

Pertama, Anda dapat mengaktifkan materialisasi hanya jika Anda telah membuat TAMPILAN biasa. Jika tidak, Anda harus menulis ulang permintaan yang tersisa untuk mengakses tampilan yang baru dibuat untuk menggunakan materialisasi ini. Atau biarkan semuanya apa adanya, tetapi setidaknya akan tidak efektif jika ada data tertentu yang sudah dihitung, tetapi banyak pertanyaan tidak selalu menggunakannya, tetapi hitung lagi.

Kedua, mereka memiliki sejumlah besar pembatasan:

Oracle
5.3.8.4 Batasan Umum tentang Refresh Cepat

Permintaan definisi tampilan terwujud dibatasi sebagai berikut:
  • Tampilan terwujud tidak boleh berisi referensi ke ekspresi tidak berulang seperti SYSDATE dan ROWNUM .
  • Tampilan terwujud tidak boleh berisi referensi ke tipe data RAW atau LONG RAW .
  • Itu tidak dapat berisi subquery daftar SELECT .
  • Itu tidak dapat berisi fungsi analitik (misalnya, RANK ) dalam klausa SELECT .
  • Itu tidak bisa referensi tabel di mana indeks XMLIndex didefinisikan.
  • Itu tidak bisa berisi klausa MODEL .
  • Itu tidak bisa mengandung klausa HAVING dengan subquery.
  • Itu tidak dapat berisi kueri bersarang yang memiliki ANY , ALL , atau NOT EXISTS .
  • Itu tidak boleh mengandung klausa [START WITH โ€ฆ] CONNECT BY .
  • Itu tidak dapat berisi beberapa tabel detail di situs yang berbeda.
  • ON COMMIT tampilan terwujud tidak dapat memiliki tabel detail jarak jauh.
  • Tampilan terwujud yang bersarang harus memiliki gabungan atau agregat.
  • Tampilan gabungan terwujud dan tampilan agregat terwujud dengan klausa GROUP BY tidak dapat memilih dari tabel yang diorganisir indeks.

5.3.8.5 Batasan tentang Perbarui Cepat pada Tampilan Terwujud dengan Hanya Bergabung

Menentukan kueri untuk tampilan terwujud hanya dengan penggabungan dan tidak ada agregat yang memiliki pembatasan penyegaran cepat berikut:
  • Semua pembatasan dari " Pembatasan Umum tentang Refresh Cepat ".
  • Mereka tidak dapat memiliki klausa atau agregat GROUP BY .
  • Baris pendek semua tabel dalam daftar FROM harus muncul di daftar SELECT dari kueri.
  • Log tampilan terwujud harus ada dengan baris baris untuk semua tabel dasar dalam daftar FROM dari permintaan.
  • Anda tidak dapat membuat tampilan terwujud cepat yang dapat disegarkan dari beberapa tabel dengan gabungan sederhana yang menyertakan kolom tipe objek dalam pernyataan SELECT .

Juga, metode penyegaran yang Anda pilih tidak akan efisien secara optimal jika:
  • Permintaan mendefinisikan menggunakan gabungan luar yang berperilaku seperti gabungan dalam. Jika kueri pendefinisian berisi gabungan seperti itu, pertimbangkan untuk menulis ulang kueri pendefinisian untuk berisi gabungan internal.
  • Daftar SELECT dari tampilan terwujud berisi ekspresi pada kolom dari beberapa tabel.

5.3.8.6 Pembatasan pada Refresh Cepat pada Tampilan Terwujud dengan Agregat

Menentukan kueri untuk tampilan terwujud dengan agregat atau gabungan memiliki batasan berikut tentang penyegaran cepat:

Penyegaran cepat didukung untuk tampilan terwujud ON COMMIT dan ON DEMAND , namun pembatasan berikut berlaku:
  • Semua tabel dalam tampilan terwujud harus memiliki log tampilan terwujud, dan log tampilan terwujud harus:
    • Berisi semua kolom dari tabel yang dirujuk dalam tampilan terwujud.
    • Tentukan dengan ROWID dan INCLUDING VALUES NEW .
    • Tentukan klausa SEQUENCE jika tabel diharapkan memiliki campuran sisipan / beban langsung, penghapusan, dan pembaruan.

  • Hanya SUM , COUNT , AVG , VARIANCE , VARIANCE , MIN dan MAX yang didukung untuk penyegaran cepat.
  • COUNT(*) harus ditentukan.
  • Fungsi agregat harus terjadi hanya sebagai bagian terluar dari ekspresi. Yaitu, agregat seperti AVG(AVG(x)) atau AVG(x) + AVG(x) tidak diperbolehkan.
  • Untuk setiap agregat seperti AVG(expr) , COUNT(expr) harus ada. Oracle merekomendasikan agar SUM(expr) dicantumkan.
  • Jika VARIANCE(expr) atau STDDEV(expr ) ditentukan, COUNT(expr) dan SUM(expr) harus ditentukan. Oracle merekomendasikan agar SUM(expr *expr) ditentukan.
  • Kolom SELECT dalam kueri mendefinisikan tidak bisa menjadi ekspresi kompleks dengan kolom dari beberapa tabel dasar. Solusi yang mungkin untuk ini adalah dengan menggunakan tampilan terwujud bersarang.
  • Daftar SELECT harus mengandung semua kolom GROUP BY .
  • Tampilan terwujud tidak didasarkan pada satu atau beberapa tabel jarak jauh.
  • Jika Anda menggunakan tipe data CHAR di kolom filter log tampilan terwujud, set karakter situs master dan tampilan terwujud harus sama.
  • Jika tampilan terwujud memiliki salah satu dari berikut ini, maka penyegaran cepat hanya didukung pada sisipan DML konvensional dan beban langsung.
    • Tampilan MIN dengan agregat MIN atau MAX
    • Tampilan SUM(expr) yang memiliki SUM(expr) tetapi tidak ada COUNT(expr)
    • Tampilan COUNT(*) tanpa COUNT(*)

    Pandangan terwujud semacam itu disebut pandangan terwujud hanya sisipan.
  • Tampilan terwujud dengan MAX atau MIN cepat disegarkan setelah menghapus atau mencampur pernyataan DML jika tidak memiliki klausa WHERE .
    Penyegaran cepat maks / mnt setelah penghapusan atau DML campuran tidak memiliki perilaku yang sama dengan kasus khusus penyisipan. Ini menghapus dan menghitung ulang nilai maks / min untuk grup yang terpengaruh. Anda harus menyadari dampak kinerjanya.
  • Tampilan terwujud dengan tampilan bernama atau subqueries dalam klausa FROM dapat disegarkan dengan cepat asalkan pandangan dapat sepenuhnya digabungkan. Untuk informasi tentang pandangan mana yang akan digabung, lihat Oracle Database SQL Language Reference .
  • Jika tidak ada gabungan luar, Anda mungkin memiliki pilihan dan bergabung sewenang-wenang dalam klausa WHERE .
  • Tampilan agregat terwujud dengan sambungan luar cepat disegarkan setelah DML konvensional dan beban langsung, asalkan hanya tabel luar yang telah dimodifikasi. Juga, batasan unik harus ada pada kolom gabungan dari tabel gabungan dalam. Jika ada gabungan luar, semua gabungan harus dihubungkan oleh AND dan harus menggunakan operator kesetaraan ( = ).
  • Untuk tampilan terwujud dengan CUBE , ROLLUP , kumpulan pengelompokan, atau gabungannya, batasan berikut ini berlaku:
    • Daftar SELECT harus berisi pengelompokan pengelompokan yang dapat berupa fungsi GROUPING_ID pada semua fungsi GROUP BY expressions atau GROUPING untuk setiap ekspresi GROUP BY . Misalnya, jika klausa GROUP BY dari tampilan material adalah " GROUP BY CUBE(a, b) ", maka daftar SELECT harus mengandung " GROUPING_ID(a, b) " atau " GROUPING(a) AND GROUPING(b) "agar tampilan terwujud menjadi cepat disegarkan.
    • GROUP BY tidak boleh menghasilkan pengelompokan duplikat. Misalnya, " GROUP BY a, ROLLUP(a, b) " tidak dapat disegarkan dengan cepat karena menghasilkan pengelompokan duplikat " (a), (a, b), AND (a) ".

5.3.8.7 Pembatasan pada Refresh Cepat pada Tampilan Terwujud dengan UNION ALL

Pandangan UNION set UNION ALL operator mendukung opsi REFRESH FAST jika kondisi berikut dipenuhi:
  • Permintaan yang menentukan harus memiliki operator UNION ALL di tingkat atas.

    Operator UNION ALL tidak dapat disematkan di dalam subquery, dengan satu pengecualian: UNION ALL dapat berada di subquery dalam klausa FROM asalkan kueri pendefinisiannya adalah dari bentuk SELECT * FROM (lihat atau subquery dengan UNION ALL ) seperti berikut ini. contoh:
      CREATE VIEW view_with_unionall AS
     (PILIH c.rowid crid, c.cust_id, 2 umarker
      DARI pelanggan c MANA c.cust_last_name = 'Smith'
      UNION ALL
      SELECT c.rowid crid, c.cust_id, 3 umarker
      DARI pelanggan c MANA c.cust_last_name = 'Jones');
    
     BUAT TAMPILAN MATERIALISASI unionall_inside_view_mv
     REFRESH CEPAT PADA PERMINTAAN SEBAGAI
     SELECT * FROM view_with_unionall;
    
    Perhatikan bahwa view view_with_unionall memenuhi persyaratan untuk refresh cepat.
  • Setiap blok permintaan dalam UNION ALL query harus memenuhi persyaratan tampilan terwujud cepat dengan agregat atau tampilan cepat terwujud dengan bergabung.

    Log tampilan terwujud yang sesuai harus dibuat pada tabel seperti yang diperlukan untuk jenis tampilan terwujud cepat yang dapat disegarkan.
    Perhatikan bahwa Oracle Database juga memungkinkan kasus khusus dari tampilan satu tabel terwujud dengan bergabung hanya jika kolom ROWID telah dimasukkan dalam daftar SELECT dan dalam log tampilan terwujud. Ini ditunjukkan dalam permintaan mendefinisikan view view_with_unionall .
  • Daftar SELECT dari setiap kueri harus menyertakan penanda UNION ALL , dan kolom UNION ALL harus memiliki nilai numerik atau string konstan yang berbeda di setiap cabang UNION ALL . Selanjutnya, kolom penanda harus muncul di posisi ordinal yang sama di daftar SELECT dari setiap blok permintaan. Lihat " UNION ALL Marker dan Query Rewrite " untuk informasi lebih lanjut mengenai UNION ALL marker.
  • Beberapa fitur seperti gabungan luar, permintaan tampilan teragregasi hanya menyisipkan agregat dan tabel jarak jauh tidak didukung untuk tampilan terwujud dengan UNION ALL . Perhatikan, bagaimanapun, bahwa pandangan terwujud yang digunakan dalam replikasi, yang tidak mengandung gabungan atau agregat, dapat dengan cepat di-refresh ketika UNION ALL atau tabel jarak jauh digunakan.
  • Parameter inisialisasi kompatibilitas harus diatur ke 9.2.0 atau lebih tinggi untuk membuat tampilan terwujud yang cepat di-refresh dengan UNION ALL .

Saya tidak ingin menyinggung penggemar Oracle, tetapi menilai dari daftar keterbatasan mereka, tampaknya mekanisme ini tidak ditulis dalam kasus umum menggunakan beberapa jenis model, tetapi ribuan orang India, di mana setiap orang diizinkan untuk menulis utas mereka sendiri, dan masing-masing dari mereka bisa dan lakukan. Menggunakan mekanisme ini untuk logika nyata seperti berjalan di ladang ranjau. Kapan saja, Anda bisa mendapatkan tambang, mengenai salah satu batasan yang tidak jelas. Bagaimana ini bekerja juga merupakan masalah yang terpisah, tetapi di luar ruang lingkup artikel ini.

Microsoft SQL Server

Persyaratan tambahan


Selain opsi SET dan persyaratan fungsi deterministik, persyaratan berikut harus dipenuhi:
  • Pengguna yang menjalankan CREATE INDEX harus menjadi pemilik tampilan.
  • Saat Anda membuat indeks, opsi IGNORE_DUP_KEY harus disetel ke OFF (pengaturan default).
  • Tabel harus direferensikan dengan nama dua bagian, skema . tablename dalam definisi tampilan.
  • Fungsi yang ditentukan pengguna yang dirujuk dalam tampilan harus dibuat dengan menggunakan opsi WITH SCHEMABINDING .
  • Setiap fungsi yang ditentukan pengguna yang dirujuk dalam tampilan harus direferensikan dengan nama dua bagian, <schema> . <fungsi> .
  • Properti akses data dari fungsi yang ditentukan pengguna harus NO SQL , dan properti akses eksternal harus NO .
  • Fungsi runtime bahasa umum (CLR) dapat muncul dalam daftar pilih tampilan, tetapi tidak dapat menjadi bagian dari definisi kunci indeks berkerumun. Fungsi CLR tidak dapat muncul dalam klausa WHERE tampilan atau klausa ON operasi JOIN dalam tampilan.
  • Fungsi dan metode CLR tipe CLR yang ditentukan pengguna yang digunakan dalam definisi tampilan harus memiliki properti yang ditetapkan seperti yang ditunjukkan pada tabel berikut.
    PropertiCatatan
    DETERMINISTIK = BENARHarus dinyatakan secara eksplisit sebagai atribut dari metode Microsoft .NET Framework.
    PRECISE = BENARHarus dinyatakan secara eksplisit sebagai atribut dari metode .NET Framework.
    AKSES DATA = TANPA SQLDitentukan dengan menetapkan atribut DataAccess ke DataAccessKind.None dan atribut SystemDataAccess ke SystemDataAccessKind.None.
    AKSES EKSTERNAL = TIDAKProperti ini default untuk TIDAK untuk rutinitas CLR.
  • Tampilan harus dibuat dengan menggunakan opsi WITH SCHEMABINDING .
  • Tampilan harus merujuk hanya tabel dasar yang ada dalam database yang sama dengan tampilan. Tampilan tidak dapat merujuk tampilan lain.
  • Pernyataan SELECT dalam definisi tampilan tidak boleh mengandung elemen Transact-SQL berikut:
    COUNTFungsi ROWSET ( OPENDATASOURCE , OPENQUERY , OPENROWSET , DAN OPENXML )OUTER bergabung ( LEFT , RIGHT , atau FULL )
    Tabel turunan (didefinisikan dengan menentukan pernyataan SELECT dalam klausa FROM )Bergabung sendiriMenentukan kolom dengan menggunakan SELECT * atau SELECT <table_name>.*
    DISTINCTSTDEV , STDEVP , VAR , VARP , atau AVGEkspresi tabel umum (CTE)
    float 1 , teks , ntext , gambar , XML , atau kolom filestreamSubqueryKlausa OVER , yang mencakup fungsi peringkat atau jendela agregat
    Predikat teks lengkap ( CONTAINS , FREETEXT )Fungsi SUM yang mereferensikan ekspresi nullableORDER BY
    Fungsi agregat yang ditentukan pengguna CLRTOPCUBE , ROLLUP , atau GROUPING SETS
    MIN , MAXUNION , EXCEPT , atau INTERSECTTABLESAMPLE
    Variabel tabelOUTER APPLY atau CROSS APPLYPIVOT , UNPIVOT
    Kumpulan kolom yang jarangFungsi bernilai inline (TVF) atau multi-pernyataan tabel (MSTVF)OFFSET
    CHECKSUM_AGG

    1 Tampilan yang diindeks dapat berisi kolom float ; Namun, kolom tersebut tidak dapat dimasukkan dalam kunci indeks berkerumun.
  • Jika GROUP BY ada, definisi VIEW harus mengandung COUNT_BIG(*) dan tidak boleh mengandung HAVING . Batasan GROUP BY ini hanya berlaku untuk definisi tampilan yang diindeks. Kueri dapat menggunakan tampilan yang diindeks dalam rencana pelaksanaannya bahkan jika itu tidak memenuhi batasan GROUP BY .
  • Jika definisi tampilan berisi klausa GROUP BY , kunci indeks berkerumun unik hanya dapat merujuk kolom yang ditentukan dalam klausa GROUP BY .

Di sini Anda dapat melihat bahwa orang India tidak tertarik, karena mereka memutuskan untuk melakukan sesuai dengan skema "kita akan berbuat sedikit, tetapi baik." Artinya, mereka memiliki lebih banyak ranjau di lapangan, tetapi lokasi mereka lebih transparan. Hal yang paling menyedihkan adalah batasan ini:
Tampilan harus merujuk hanya tabel dasar yang ada dalam database yang sama dengan tampilan. Tampilan tidak dapat merujuk tampilan lain.

Dalam terminologi kami, ini berarti bahwa suatu fungsi tidak dapat mengakses fungsi terwujud lainnya. Ini memotong seluruh ideologi sejak awal.
Juga, batasan ini (dan selanjutnya dalam teks) sangat mengurangi kasus penggunaan:
Pernyataan SELECT dalam definisi tampilan tidak boleh mengandung elemen Transact-SQL berikut:
COUNTFungsi ROWSET ( OPENDATASOURCE , OPENQUERY , OPENROWSET , DAN OPENXML )OUTER bergabung ( LEFT , RIGHT , atau FULL )
Tabel turunan (didefinisikan dengan menentukan pernyataan SELECT dalam klausa FROM )Bergabung sendiriMenentukan kolom dengan menggunakan SELECT * atau SELECT <table_name>.*
DISTINCTSTDEV , STDEVP , VAR , VARP , atau AVGEkspresi tabel umum (CTE)
float 1 , teks , ntext , gambar , XML , atau kolom filestreamSubqueryKlausa OVER , yang mencakup fungsi peringkat atau jendela agregat
Predikat teks lengkap ( CONTAINS , FREETEXT )Fungsi SUM yang mereferensikan ekspresi nullableORDER BY
Fungsi agregat yang ditentukan pengguna CLRTOPCUBE , ROLLUP , atau GROUPING SETS
MIN , MAXUNION , EXCEPT , atau INTERSECTTABLESAMPLE
Variabel tabelOUTER APPLY atau CROSS APPLYPIVOT , UNPIVOT
Kumpulan kolom yang jarangFungsi bernilai inline (TVF) atau multi-pernyataan tabel (MSTVF)OFFSET
CHECKSUM_AGG

GABUNG LUAR, UNION, ORDER OLEH, dan lainnya dilarang. Mungkin lebih mudah untuk menunjukkan apa yang bisa digunakan daripada apa yang tidak. Daftarnya mungkin jauh lebih kecil.

Untuk meringkas: satu set besar pembatasan di masing-masing (saya perhatikan komersial) DBMS vs tidak ada (dengan pengecualian satu logis daripada teknis) dalam teknologi LGPL. Namun, perlu dicatat bahwa menerapkan mekanisme ini dalam logika relasional agak lebih rumit daripada fungsional yang dijelaskan.

Implementasi


Bagaimana cara kerjanya? PostgreSQL digunakan sebagai "mesin virtual". Di dalamnya ada algoritma kompleks yang membangun kueri. Ini kode sumbernya . Dan tidak hanya ada satu set heuristik dengan sekelompok seandainya. Jadi, jika Anda memiliki beberapa bulan untuk belajar, maka Anda dapat mencoba memahami arsitekturnya.

Apakah ini bekerja secara efisien? Cukup efektif. Sayangnya, membuktikan ini sulit. Saya hanya bisa mengatakan bahwa jika Anda mempertimbangkan ribuan permintaan yang ada dalam aplikasi besar, maka secara rata-rata permintaan itu lebih efektif daripada pengembang yang baik. Seorang programmer SQL yang sangat baik dapat menulis permintaan apa pun dengan lebih efisien, tetapi dengan ribuan pertanyaan, ia tidak akan memiliki motivasi atau waktu untuk melakukan ini. Satu-satunya hal yang dapat saya berikan sebagai bukti keefektifan adalah bahwa berdasarkan platform yang dibangun pada DBMS ini, beberapa proyek sistem ERP bekerja di mana terdapat ribuan fungsi MATERIALISASI yang berbeda, dengan ribuan pengguna dan basis data terrabyte dengan ratusan juta catatan yang berfungsi pada server prosesor ganda biasa. Namun, siapa pun dapat menguji / menyangkal keefektifannya dengan mengunduh platform dan PostgreSQL, mengaktifkan pencatatan query SQL dan mencoba mengubah logika dan data di sana.

Dalam artikel berikut, saya juga akan berbicara tentang bagaimana Anda dapat menggantung pembatasan pada fungsi, bekerja dengan sesi perubahan, dan banyak lagi.

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


All Articles