Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Menyesuaikan Pasokan Dengan Permintaan — Solusi, Bagian 1

[ Langsung ke:Tantangan asli | Solusi:Bagian 1 | Bagian 2 | Bagian 3]

Bulan lalu, saya membahas teka-teki Peter Larsson tentang mencocokkan penawaran dengan permintaan. Saya menunjukkan solusi berbasis kursor langsung Peter dan menjelaskan bahwa itu memiliki penskalaan linier. Tantangan yang saya berikan kepada Anda adalah mencoba dan menghasilkan solusi berbasis himpunan untuk tugas tersebut, dan anak laki-laki, buat orang-orang bangkit untuk menghadapi tantangan itu! Terima kasih Luca, Kamil Kosno, Daniel Brown, Brian Walker, Joe Obbish, Rainer Hoffmann, Paul White, Charlie, dan, tentu saja, Peter Larsson, untuk mengirimkan solusi Anda. Beberapa idenya sangat brilian dan mengejutkan.

Bulan ini, saya akan mulai menjelajahi solusi yang diajukan, secara kasar, mulai dari yang berkinerja buruk hingga yang berkinerja terbaik. Mengapa repot-repot dengan yang berkinerja buruk? Karena Anda masih bisa belajar banyak dari mereka; misalnya, dengan mengidentifikasi anti-pola. Memang, upaya pertama untuk memecahkan tantangan ini bagi banyak orang, termasuk saya dan Peter, didasarkan pada konsep persimpangan interval. Kebetulan teknik klasik berbasis predikat untuk mengidentifikasi persimpangan interval memiliki kinerja yang buruk karena tidak ada skema pengindeksan yang baik untuk mendukungnya. Artikel ini didedikasikan untuk pendekatan berkinerja buruk ini. Meskipun kinerjanya buruk, mengerjakan solusi adalah latihan yang menarik. Hal ini membutuhkan latihan keterampilan pemodelan masalah dengan cara yang cocok untuk pengobatan berbasis set. Menarik juga untuk mengidentifikasi penyebab kinerja yang buruk, sehingga lebih mudah untuk menghindari anti-pola di masa depan. Perlu diingat, solusi ini hanyalah titik awal.

DDL dan Kumpulan Kecil Data Sampel

Sebagai pengingat, tugas melibatkan kueri tabel yang disebut "Lelang."" Gunakan kode berikut untuk membuat tabel dan mengisinya dengan kumpulan kecil data sampel:

DROP TABLE JIKA ADA dbo.Auctions; CREATE TABLE dbo.Auctions( ID INT NOT NULL IDENTITY(1, 1) CONSTRAINT pk_Auctions PRIMARY KEY CLUSTERED, Code CHAR(1) NOT NULL CONSTRAINT ck_Auctions_Code CHECK (Kode ='D' ATAU Kode ='S'), Kuantitas DECIMAL(19 , 6) NOT NULL CONSTRAINT ck_Auctions_Quantity CHECK (Jumlah> 0)); SET NOCOUNT AKTIF; HAPUS DARI dbo.Auctions; SET IDENTITY_INSERT dbo.Auctions AKTIF; INSERT INTO dbo.Auctions(ID, Code, Quantity) NILAI (1, 'D', 5.0), (2, 'D', 3.0), (3, 'D', 8.0), (5, 'D', 2.0), (6, 'D', 8.0), (7, 'D', 4.0), (8, 'D', 2.0), (1000, 'S', 8.0), (2000, 'S', 6.0), (3000, 'S', 2.0), (4000, 'S', 2.0), (5000, 'S', 4.0), (6000, 'S', 3.0), (7000, 'S', 2.0); SET IDENTITY_INSERT dbo.Auctions NONAKTIF;

Tugas Anda adalah membuat pasangan yang cocok dengan entri penawaran dengan permintaan berdasarkan urutan ID, menuliskannya ke tabel sementara. Berikut adalah hasil yang diinginkan untuk kumpulan kecil data sampel:

DemandID SupplyID TradeQuantity----------- ----------- --------------1 1000 5.0000002 1000 3.000.0003 2000 6.000003 3000 2.0000005 4000 2.0000006 5000 4.0000006 6000 3.000.0006 7000 1.000.0007 7000 1.000.000

Bulan lalu, saya juga menyediakan kode yang dapat Anda gunakan untuk mengisi tabel Lelang dengan sekumpulan besar sampel data, mengontrol jumlah entri penawaran dan permintaan serta kisaran kuantitasnya. Pastikan Anda menggunakan kode dari artikel bulan lalu untuk memeriksa kinerja solusi.

Memodelkan Data sebagai Interval

Satu ide menarik yang cocok untuk mendukung solusi berbasis himpunan adalah memodelkan data sebagai interval. Dengan kata lain, mewakili setiap entri permintaan dan penawaran sebagai interval dimulai dengan jumlah total berjalan dari jenis yang sama (permintaan atau penawaran) hingga tetapi tidak termasuk arus, dan diakhiri dengan total berjalan termasuk arus, tentu saja berdasarkan ID Memerintah. Misalnya, melihat kumpulan kecil data sampel, entri permintaan pertama (ID 1) adalah untuk jumlah 5,0 dan yang kedua (ID 2) adalah untuk jumlah 3,0. Entri permintaan pertama dapat direpresentasikan dengan interval mulai:0.0, akhir:5.0, dan yang kedua dengan interval mulai:5.0, akhir:8.0, dan seterusnya.
Demikian pula, entri penawaran pertama (ID 1000) adalah untuk jumlah 8,0 dan yang kedua (ID 2000) adalah untuk jumlah 6,0. Entri persediaan pertama dapat direpresentasikan dengan interval mulai:0.0, akhir:8.0, dan yang kedua dengan interval mulai:8.0, akhir:14.0, dan seterusnya.

Pasangan permintaan-penawaran yang perlu Anda buat adalah segmen yang tumpang tindih dari interval yang berpotongan di antara kedua jenis tersebut.

Ini mungkin paling baik dipahami dengan penggambaran visual dari pemodelan data berbasis interval dan hasil yang diinginkan, seperti yang ditunjukkan pada Gambar 1.

Gambar 1:Memodelkan Data sebagai Interval

Penggambaran visual pada Gambar 1 cukup jelas tetapi, singkatnya…

Persegi panjang biru mewakili entri permintaan sebagai interval, menunjukkan jumlah total lari eksklusif sebagai awal interval dan total lari inklusif sebagai akhir interval. Persegi panjang kuning melakukan hal yang sama untuk entri persediaan. Kemudian perhatikan bagaimana segmen yang tumpang tindih dari interval berpotongan dari dua jenis, yang digambarkan oleh persegi panjang hijau, adalah pasangan permintaan-penawaran yang perlu Anda hasilkan. Misalnya, pasangan hasil pertama adalah dengan ID permintaan 1, ID penawaran 1000, jumlah 5. Hasil pasangan kedua adalah dengan ID permintaan 2, ID penawaran 1000, jumlah 3. Dan seterusnya.

Persimpangan Interval Menggunakan CTE

Sebelum Anda mulai menulis kode T-SQL dengan solusi berdasarkan ide pemodelan interval, Anda seharusnya sudah memiliki pemahaman intuitif tentang indeks apa yang mungkin berguna di sini. Karena Anda cenderung menggunakan fungsi jendela untuk menghitung total berjalan, Anda bisa mendapatkan keuntungan dari indeks penutup dengan kunci berdasarkan kolom Kode, ID, dan termasuk kolom Kuantitas. Berikut kode untuk membuat indeks seperti itu:

BUAT INDEKS NONCLUSTERED UNIK idx_Code_ID_i_Quantity PADA dbo.Auctions(Code, ID) INCLUDE(Quantity);

Itu indeks yang sama yang saya rekomendasikan untuk solusi berbasis kursor yang saya bahas bulan lalu.

Juga, ada potensi di sini untuk mendapatkan keuntungan dari pemrosesan batch. Anda dapat mengaktifkan pertimbangannya tanpa persyaratan mode batch di rowstore, misalnya, menggunakan SQL Server 2019 Enterprise atau yang lebih baru, dengan membuat indeks dummy columnstore berikut:

BUAT INDEKS COLUMNSTORE NONCLUSTERED idx_cs PADA dbo.Auctions(ID) WHERE ID =-1 AND ID =-2;

Sekarang Anda dapat mulai mengerjakan kode T-SQL solusi.

Kode berikut membuat interval yang mewakili entri permintaan:

DENGAN D0 AS-- D0 menghitung permintaan yang berjalan sebagai EndDemand( SELECT ID, Quantity, SUM(Quantity) OVER(ORDER BY ID ROWS UNBOUNDED PRECEDING) AS EndDemand FROM dbo.Auctions WHERE Code ='D'),-- D mengekstrak EndDemand sebelumnya sebagai StartDemand, menyatakan permintaan awal-akhir sebagai intervalD AS( SELECT ID, Quantity, EndDemand - Quantity AS StartDemand, EndDemand FROM D0)SELECT *FROM D;

Kueri yang mendefinisikan CTE D0 menyaring entri permintaan dari tabel Lelang dan menghitung jumlah total yang berjalan sebagai pembatas akhir dari interval permintaan. Kemudian kueri yang mendefinisikan CTE kedua disebut kueri D D0 dan menghitung pembatas awal dari interval permintaan dengan mengurangkan kuantitas saat ini dari pembatas akhir.

Kode ini menghasilkan output berikut:

ID Kuantitas StartDemand EndDemand---------------- ------------ ----------1 5.000.000 0.000000 5.000.0002 3.000.000 5.000.000 8.000.0003 8.000.000 8.000.000 16.0000005 2.00000 16.000.000 18.000.0006 8.000.000 18.000.000 26.0000007 4.000.000 26.000.000 30.0000008 2.00000 30.000000 32.000000

Interval suplai dihasilkan sangat mirip dengan menerapkan logika yang sama ke entri suplai, menggunakan kode berikut:

DENGAN S0 AS-- S0 menghitung suplai yang berjalan sebagai EndSupply( SELECT ID, Quantity, SUM(Quantity) OVER(ORDER BY ID ROWS UNBOUNDED PRECEDING) AS EndSupply FROM dbo.Auctions WHERE Code ='S'),-- S ekstrak sebelumnya EndSupply sebagai StartSupply, menyatakan pasokan awal-akhir sebagai interval AS( SELECT ID, Quantity, EndSupply - Quantity AS StartSupply, EndSupply FROM S0)SELECT *FROM S;

Kode ini menghasilkan output berikut:

ID Kuantitas MulaiSupply EndSupply----- --------- ------------ ----------1000 8.000.000 0.000000 8.000.0002000 6.000.000 8.000.000 14.000003000 2.000000 14.000.000 16.0000004000 2.00000 16.00000 18.000.0005000 4.000.000 18.000.000 22.0000006000 3.000.000 22.000000 25.0000007000 2.00000 25.000000 27.000000

Yang tersisa kemudian adalah mengidentifikasi interval permintaan dan penawaran yang berpotongan dari CTE D dan S, dan menghitung segmen yang tumpang tindih dari interval yang berpotongan tersebut. Ingat pasangan hasil harus ditulis ke dalam tabel sementara. Ini dapat dilakukan dengan menggunakan kode berikut:

-- Jatuhkan tabel temp jika adaDROP TABLE JIKA ADA #MyPairings; DENGAN D0 AS-- D0 menghitung permintaan yang berjalan sebagai EndDemand( SELECT ID, Quantity, SUM(Quantity) OVER(ORDER BY ID ROWS UNBOUNDED PRECEDING) AS EndDemand FROM dbo.Auctions WHERE Code ='D'),-- D extracts prev EndDemand sebagai StartDemand, menyatakan permintaan awal-akhir sebagai intervalD AS( SELECT ID, Quantity, EndDemand - Quantity AS StartDemand, EndDemand FROM D0),S0 AS-- S0 menghitung running supply sebagai EndSupply( SELECT ID, Quantity, SUM(Quantity) OVER (ORDER BY ID ROWS UNBOUNDED SEBELUMNYA) SEBAGAI EndSupply FROM dbo.Auctions WHERE Code ='S'),-- S mengekstrak prev EndSupply sebagai StartSupply, menyatakan suplai awal-akhir sebagai interval AS( SELECT ID, Quantity, EndSupply - Quantity AS StartSupply, EndSupply FROM S0)-- Permintaan luar mengidentifikasi perdagangan sebagai segmen yang tumpang tindih dari interval yang berpotongan-- Dalam interval permintaan dan penawaran yang berpotongan, kuantitas perdagangan kemudian -- LEAST(EndDemand, EndSupply) - GREATEST(StartDemsnad, StartSupply)PILIH D.ID SEBAGAI DemandID, S.ID SEBAGAI SupplyID, CASE WH EN EndDemand  StartSupply MAKA StartDemand ELSE StartSupply AKHIR SEBAGAI TradeQuantityINTO #MyPairingsFROM D INNER JOIN S ON D.StartDemand 
 Selain kode yang membuat interval permintaan dan penawaran, yang telah Anda lihat sebelumnya, tambahan utama di sini adalah kueri luar, yang mengidentifikasi interval berpotongan antara D dan S, dan menghitung segmen yang tumpang tindih. Untuk mengidentifikasi interval yang berpotongan, outer query menggabungkan D dan S menggunakan predikat join berikut:

D.StartDemand  S.StartSupply

Itulah predikat klasik untuk mengidentifikasi perpotongan interval. Ini juga merupakan sumber utama kinerja buruk solusi, seperti yang akan saya jelaskan segera.

Kueri luar juga menghitung kuantitas perdagangan dalam daftar SELECT sebagai:

LEAST(EndDemand, EndSupply) - TERBESAR(StartDemand, StartSupply)

Jika Anda menggunakan Azure SQL, Anda bisa menggunakan ekspresi ini. Jika Anda menggunakan SQL Server 2019 atau versi lebih lama, Anda dapat menggunakan alternatif yang setara secara logis berikut:

CASE WHEN EndDemand  StartSupply THEN StartDemand ELSE StartSupply END

Karena persyaratannya adalah untuk menulis hasilnya ke dalam tabel sementara, kueri luar menggunakan pernyataan SELECT INTO untuk mencapainya.

Ide untuk memodelkan data sebagai interval jelas menarik dan elegan. Tapi bagaimana dengan kinerja? Sayangnya, solusi khusus ini memiliki masalah besar terkait dengan bagaimana persimpangan interval diidentifikasi. Periksa rencana untuk solusi ini yang ditunjukkan pada Gambar 2.

Gambar 2:Rencana Kueri untuk Persimpangan Menggunakan Solusi CTE

Mari kita mulai dengan bagian paket yang murah.

Input luar dari gabungan Nested Loops menghitung interval permintaan. Ini menggunakan operator Pencarian Indeks untuk mengambil entri permintaan, dan operator Agregat Jendela mode batch untuk menghitung pembatas akhir interval permintaan (disebut sebagai Expr1005 dalam rencana ini). Pembatas awal interval permintaan adalah Ekspr1005 – Kuantitas (dari D).

Sebagai catatan tambahan, Anda mungkin menemukan penggunaan operator Sortir eksplisit sebelum operator Agregat Jendela mode batch mengejutkan di sini, karena entri permintaan yang diambil dari Pencarian Indeks sudah diurutkan oleh ID seperti yang dibutuhkan oleh fungsi jendela. Ini berkaitan dengan fakta bahwa saat ini, SQL Server tidak mendukung kombinasi efisien operasi indeks pelestarian urutan paralel sebelum operator Agregat Jendela mode batch paralel. Jika Anda memaksakan rencana serial hanya untuk tujuan eksperimen, Anda akan melihat operator Sortir menghilang. SQL Server memutuskan secara keseluruhan, penggunaan paralelisme di sini lebih disukai, meskipun menghasilkan penyortiran eksplisit tambahan. Tetapi sekali lagi, bagian dari rencana ini mewakili sebagian kecil pekerjaan dalam skema besar.

Demikian pula, input bagian dalam dari Nested Loops join dimulai dengan menghitung interval suplai. Anehnya, SQL Server memilih untuk menggunakan operator mode baris untuk menangani bagian ini. Di satu sisi, operator mode baris yang digunakan untuk menghitung total berjalan melibatkan lebih banyak overhead daripada alternatif Agregat Jendela mode batch; di sisi lain, SQL Server memiliki implementasi paralel yang efisien dari operasi indeks pelestarian pesanan yang diikuti oleh perhitungan fungsi jendela, menghindari Penyortiran eksplisit untuk bagian ini. Anehnya, pengoptimal memilih satu strategi untuk interval permintaan dan satu lagi untuk interval pasokan. Bagaimanapun, operator Index Seek mengambil entri suplai, dan urutan operator berikutnya hingga operator Compute Scalar menghitung pembatas akhir interval suplai (disebut sebagai Expr1009 dalam rencana ini). Pembatas awal interval suplai kemudian Expr1009 – Kuantitas (dari S).

Terlepas dari banyaknya teks yang saya gunakan untuk menggambarkan dua bagian ini, bagian yang benar-benar mahal dari pekerjaan dalam rencana adalah apa yang terjadi selanjutnya.

Bagian selanjutnya perlu menggabungkan interval permintaan dan interval penawaran menggunakan predikat berikut:

D.StartDemand  S.StartSupply

Tanpa indeks pendukung, dengan asumsi interval permintaan DI dan interval suplai SI, ini akan melibatkan pemrosesan baris DI * SI. Rencana pada Gambar 2 dibuat setelah mengisi tabel Lelang dengan 400.000 baris (200.000 entri permintaan dan 200.000 entri pasokan). Jadi, tanpa indeks pendukung, rencana tersebut perlu memproses 200.000 * 200.000 =40.000.000.000 baris. Untuk mengurangi biaya ini, pengoptimal memilih untuk membuat indeks sementara (lihat operator Index Spool) dengan pembatas akhir interval suplai (Expr1009) sebagai kuncinya. Itu cukup banyak yang terbaik yang bisa dilakukan. Namun, ini hanya menangani sebagian dari masalah. Dengan dua predikat rentang, hanya satu yang dapat didukung oleh predikat pencarian indeks. Yang lain harus ditangani menggunakan predikat residual. Memang, Anda dapat melihat dalam rencana bahwa pencarian dalam indeks sementara menggunakan predikat pencarian Expr1009> Expr1005 – D.Quantity, diikuti oleh operator Filter yang menangani predikat residual Expr1005> Expr1009 – S.Quantity.

Dengan asumsi rata-rata, predikat seek mengisolasi setengah baris penawaran dari indeks per baris permintaan, jumlah total baris yang dipancarkan dari operator Index Spool dan diproses oleh operator Filter adalah DI * SI / 2. Dalam kasus kami, dengan 200.000 baris permintaan dan 200.000 baris penawaran, ini berarti 20.000.000.000. Memang, panah yang berpindah dari operator Index Spool ke operator Filter melaporkan sejumlah baris yang mendekati ini.

Paket ini memiliki penskalaan kuadrat, dibandingkan dengan penskalaan linier dari solusi berbasis kursor dari bulan lalu. Anda dapat melihat hasil uji kinerja yang membandingkan dua solusi pada Gambar 3. Anda dapat dengan jelas melihat parabola yang berbentuk bagus untuk solusi berbasis himpunan.

Gambar 3:Kinerja Persimpangan Menggunakan Solusi CTE Versus Solusi Berbasis Kursor

Persimpangan Interval Menggunakan Tabel Sementara

Anda dapat sedikit memperbaiki keadaan dengan mengganti penggunaan CTE untuk interval permintaan dan penawaran dengan tabel sementara, dan untuk menghindari gulungan indeks, membuat indeks Anda sendiri pada tabel sementara dengan memegang interval pasokan dengan pembatas akhir sebagai kuncinya. Berikut kode solusi lengkapnya:

-- Jatuhkan tabel temp jika adaDROP TABLE JIKA ADA #MyPairings, #Demand, #Supply; DENGAN D0 AS-- D0 menghitung permintaan yang berjalan sebagai EndDemand( SELECT ID, Quantity, SUM(Quantity) OVER(ORDER BY ID ROWS UNBOUNDED PRECEDING) AS EndDemand FROM dbo.Auctions WHERE Code ='D'),-- D extracts prev EndDemand sebagai StartDemand, menyatakan permintaan awal-akhir sebagai intervalD AS( SELECT ID, Quantity, EndDemand - Quantity AS StartDemand, EndDemand FROM D0)SELECT ID, Quantity, CAST(ISNULL(StartDemand, 0.0) AS DECIMAL(19, 6)) AS StartDemand, CAST(ISNULL(EndDemand, 0.0) AS DECIMAL(19, 6)) AS EndDemandINTO #DemandFROM D;WITH S0 AS-- S0 menghitung suplai yang berjalan sebagai EndSupply( SELECT ID, Quantity, SUM(Quantity) OVER(ORDER BY ID BARIS UNBOUNDED SEBELUMNYA) SEBAGAI EndSupply FROM dbo.Auctions WHERE Code ='S'),-- S mengekstrak prev EndSupply sebagai StartSupply, menyatakan suplai awal-akhir sebagai interval AS( SELECT ID, Quantity, EndSupply - Quantity AS StartSupply, EndSupply FROM S0)PILIH ID, Kuantitas, CAST(ISNULL(StartSupply, 0.0) SEBAGAI DESIMAL(19, 6)) SEBAGAI StartSupply, CAST(ISNULL(EndSupply, 0.0) SEBAGAI DESIMAL(19, 6)) SEBAGAI EndSupplyINTO #SupplyFROM S; BUAT INDEKS CLUSTERED UNIK idx_cl_ES_ID PADA #Supply(EndSupply, ID); -- Kueri luar mengidentifikasi perdagangan sebagai segmen yang tumpang tindih dari interval yang berpotongan-- Dalam interval permintaan dan penawaran yang berpotongan, kuantitas perdagangan kemudian -- LEAST(EndDemand, EndSupply) - GREATEST(StartDemsnad, StartSupply)PILIH D.ID SEBAGAI DemandID, S.ID AS SupplyID, CASE WHEN EndDemand  StartSupply THE StartDemand ELSE StartSupply END AS TradeQuantityINTO #MyPairingsFROM #Demand SEBAGAI D INNER ASEE JOIN (FORCLE ASUP. S.EndSupply DAN D.EndDemand> S.StartSupply;

Rencana untuk solusi ini ditunjukkan pada Gambar 4:

Gambar 4:Rencana Kueri untuk Persimpangan Menggunakan Solusi Tabel Temp

Dua rencana pertama menggunakan kombinasi mode batch Index Seek + Sort + Window Aggregate operator untuk menghitung interval penawaran dan permintaan dan menuliskannya ke tabel sementara. Paket ketiga menangani pembuatan indeks pada tabel #Supply dengan pembatas EndSupply sebagai kunci utama.

Paket keempat sejauh ini mewakili sebagian besar pekerjaan, dengan operator gabungan Nested Loops yang cocok dengan setiap interval dari #Demand, interval berpotongan dari #Supply. Perhatikan juga di sini, operator Pencarian Indeks mengandalkan predikat #Supply.EndSupply> #Demand.StartDemand sebagai predikat pencarian, dan #Demand.EndDemand> #Supply.StartSupply sebagai predikat residual. Jadi dalam hal kompleksitas/penskalaan, Anda mendapatkan kompleksitas kuadrat yang sama seperti untuk solusi sebelumnya. Anda hanya membayar lebih sedikit per baris karena Anda menggunakan indeks Anda sendiri daripada spool indeks yang digunakan oleh paket sebelumnya. Anda dapat melihat kinerja solusi ini dibandingkan dengan dua solusi sebelumnya pada Gambar 5.

Gambar 5:Kinerja Persimpangan menggunakan tabel temp dibandingkan dengan dua solusi lainnya

Seperti yang Anda lihat, solusi dengan tabel temp berperforma lebih baik daripada solusi dengan CTE, tetapi masih memiliki penskalaan kuadrat dan kinerjanya sangat buruk dibandingkan dengan kursor.

Apa Selanjutnya?

Artikel ini membahas upaya pertama dalam menangani tugas pencocokan pasokan klasik dengan permintaan menggunakan solusi berbasis himpunan. Idenya adalah untuk memodelkan data sebagai interval, mencocokkan penawaran dengan entri permintaan dengan mengidentifikasi interval penawaran dan permintaan yang berpotongan, dan kemudian menghitung kuantitas perdagangan berdasarkan ukuran segmen yang tumpang tindih. Tentu saja ide yang menarik. Masalah utama dengan itu juga masalah klasik mengidentifikasi persimpangan interval dengan menggunakan dua predikat rentang. Bahkan dengan indeks terbaik, Anda hanya dapat mendukung satu predikat rentang dengan pencarian indeks; predikat rentang lainnya harus ditangani menggunakan predikat residual. Ini menghasilkan rencana dengan kompleksitas kuadrat.

Lalu apa yang bisa Anda lakukan untuk mengatasi kendala tersebut? Ada beberapa ide yang berbeda. Satu ide brilian milik Joe Obbish, yang dapat Anda baca secara detail di posting blognya. Saya akan membahas ide-ide lain di artikel mendatang dalam seri ini.

[ Langsung ke:Tantangan asli | Solusi:Bagian 1 | Bagian 2 | Bagian 3]

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL SELECT untuk Pemula

  2. Mitos Performa :Truncate Tidak Dapat Digulung Kembali

  3. ScyllaDB Trends – Bagaimana Pengguna Menyebarkan Basis Data Besar Real-Time

  4. SQL Self Gabung

  5. Bermigrasi dari AnswerHub ke WordPress:Kisah 10 Teknologi