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

Panduan Utama Anda untuk Bergabung dengan SQL:INNER JOIN – Bagian 1

Gabung dalam, gabung luar, gabung silang? Apa yang memberi?

Ini pertanyaan yang valid. Saya pernah melihat kode Visual Basic dengan kode T-SQL yang tertanam di dalamnya. Kode VB mengambil record tabel dengan beberapa pernyataan SELECT, satu SELECT * per tabel. Kemudian, ini menggabungkan beberapa set hasil menjadi satu set rekaman. Tidak masuk akal?

Bagi para pengembang muda yang melakukannya, ternyata tidak. Tetapi ketika mereka meminta saya untuk mengevaluasi mengapa sistemnya lambat, masalah itu adalah yang pertama menarik perhatian saya. Betul sekali. Mereka tidak pernah mendengar tentang SQL bergabung. Dalam keadilan bagi mereka, mereka jujur ​​dan terbuka terhadap saran.

Bagaimana Anda menggambarkan gabungan SQL? Mungkin, Anda ingat satu lagu – Bayangkan oleh John Lennon:

Anda mungkin mengatakan saya seorang pemimpi, tapi saya bukan satu-satunya.

Saya harap suatu hari nanti Anda akan bergabung dengan kami, dan dunia akan menjadi satu.

Dalam konteks lagu, bergabung adalah menyatukan. Dalam database SQL, menggabungkan catatan dari 2 tabel atau lebih menjadi satu kumpulan hasil membentuk gabungan .

Artikel ini adalah awal dari seri 3 bagian yang berbicara tentang gabungan SQL:

  • GABUNG DALAM
  • OUTER JOIN, yang mencakup KIRI, KANAN, dan PENUH
  • GABUNG LINTAS

Namun sebelum kita mulai membahas INNER JOIN, mari kita uraikan join secara umum.

Selengkapnya Tentang SQL JOIN

Gabungan muncul tepat setelah klausa FROM. Dalam bentuknya yang paling sederhana, sepertinya menggunakan standar SQL-92:

FROM <table source> [<alias1>]
<join type> JOIN <table source> [<alias2>] [ON <join condition>] 
[<join type> JOIN <table source> [<alias3>] [ON <join condition>]
<join type> JOIN <table source> [<aliasN>] [ON <join condition>]]
[WHERE <condition>]

Mari kita jelaskan hal-hal sehari-hari seputar JOIN.

Sumber Tabel

Anda dapat menambahkan hingga 256 sumber tabel, menurut Microsoft. Tentu saja, itu tergantung pada sumber daya server Anda. Saya tidak pernah bergabung lebih dari 10 tabel dalam hidup saya, belum lagi 256. Bagaimanapun, sumber tabel dapat berupa salah satu dari berikut:

  • Tabel
  • Lihat
  • Meja atau melihat sinonim
  • Variabel tabel
  • Fungsi bernilai tabel
  • Tabel turunan

Alias ​​Tabel

Alias ​​​​adalah opsional, tetapi memperpendek kode Anda dan meminimalkan pengetikan. Ini juga membantu Anda menghindari kesalahan saat nama kolom ada di dua atau lebih tabel yang digunakan dalam SELECT, UPDATE, INSERT, atau DELETE. Ini juga menambah kejelasan pada kode Anda. Ini opsional, tetapi saya sarankan menggunakan alias. (Kecuali Anda suka mengetik sumber tabel berdasarkan nama.)

Kondisi Bergabung

Kata kunci ON mendahului kondisi gabung yang dapat berupa kolom gabungan tunggal atau kolom 2 kunci dari 2 tabel yang digabungkan. Atau bisa juga gabungan gabungan menggunakan lebih dari 2 kolom kunci. Ini mendefinisikan bagaimana tabel terkait.

Namun, kami menggunakan kondisi join hanya untuk INNER dan OUTER join. Menggunakannya pada CROSS JOIN akan memicu kesalahan.

Karena kondisi join menentukan hubungan, mereka membutuhkan operator.

Operator kondisi gabungan yang paling umum adalah operator persamaan (=). Operator lain seperti> atau

SQL GABUNG vs. Subkueri

Sebagian besar gabungan dapat ditulis ulang sebagai subkueri dan sebaliknya. Lihat artikel ini untuk mempelajari lebih lanjut tentang subkueri dibandingkan dengan bergabung.

Gabung dan Turunkan Tabel

Menggunakan tabel turunan dalam gabungan terlihat seperti ini:

FROM table1 a
INNER JOIN (SELECT y.column3 from table2 x
            INNER JOIN table3 y on x.column1 = y.column1) b ON a.col1 = b.col2

Itu bergabung dari hasil pernyataan SELECT lain, dan itu benar-benar valid.

Anda akan memiliki lebih banyak contoh, tetapi mari kita bahas satu hal terakhir tentang SQL JOINS. Ini adalah bagaimana proses Pengoptimal Kueri SQL Server bergabung.

Bagaimana Proses SQL Server Bergabung

Untuk memahami cara kerja proses, Anda perlu mengetahui tentang dua jenis operasi yang terlibat:

  • Operasi logis sesuai dengan jenis gabungan yang digunakan dalam kueri:INNER, OUTER, atau CROSS. Anda, sebagai pengembang, menentukan bagian pemrosesan ini saat membentuk kueri.
  • Operasi fisik – Pengoptimal Kueri memilih operasi fisik terbaik yang berlaku untuk bergabung Anda. Yang terbaik berarti tercepat untuk menghasilkan hasil. Rencana Eksekusi kueri Anda akan menampilkan operator gabungan fisik yang dipilih. Operasi ini adalah:
    • Penggabungan Loop Bersarang. Operasi ini cepat jika salah satu dari dua tabel kecil dan yang kedua besar dan diindeks. Ini membutuhkan I/O paling sedikit dengan perbandingan paling sedikit, tetapi tidak baik untuk kumpulan hasil yang besar.
    • Gabung Bergabung. Ini adalah operasi tercepat untuk kumpulan hasil yang besar dan diurutkan berdasarkan kolom yang digunakan dalam gabungan.
    • Hash Gabung. Pengoptimal kueri menggunakannya saat kumpulan hasil terlalu besar untuk Nested Loop, dan input tidak disortir untuk gabungan Gabung. Sebuah hash lebih efisien daripada mengurutkannya terlebih dahulu dan menerapkan Gabung gabung.
    • Gabung Adaptif. Dimulai dengan SQL Server 2017, ini memungkinkan pilihan antara loop bersarang atau hash . Metode join ditangguhkan hingga input pertama dipindai. Operasi ini secara dinamis beralih ke gabungan fisik yang lebih baik tanpa kompilasi ulang.

Mengapa Kita Perlu Repot Dengan Ini?

Satu kata:Performa.

Satu hal adalah mengetahui cara membentuk kueri dengan gabungan untuk menghasilkan hasil yang benar. Satu lagi adalah membuatnya berjalan secepat mungkin. Anda harus ekstra hati-hati tentang hal ini jika Anda ingin reputasi yang baik dengan pengguna Anda.

Jadi, apa yang perlu Anda perhatikan dalam Rencana Eksekusi untuk operasi logis ini?

  • Misalkan operator Sortir mendahului Gabung Gabung . Operasi sortir ini mahal untuk tabel besar (Gambar 2). Anda dapat memperbaikinya dengan mengurutkan terlebih dahulu tabel input di gabungan.
  • Misalkan ada duplikat di tabel input Gabung Gabung . SQL Server akan menulis duplikat tabel kedua ke dalam WorkTable di tempdb. Kemudian, itu akan membuat perbandingan di sana. STATISTICS IO akan mengungkapkan Tabel Kerja apa pun yang terlibat.
  • Saat data besar tumpah ke tempdb di Hash jo di, STATISTICS IO akan mengungkapkan pembacaan logis yang besar pada WorkFiles atau WorkTables. Peringatan juga akan muncul di Execution Plan (Gambar 3). Anda dapat menerapkan dua hal:pra-urutkan tabel input atau kurangi gabungan, jika memungkinkan. Akibatnya, Pengoptimal Kueri dapat memilih gabungan fisik lainnya.

Petunjuk Bergabung

Petunjuk bergabung adalah hal baru di SQL Server 2019. Saat Anda menggunakannya dalam bergabung, ini memberi tahu pengoptimal kueri untuk berhenti memutuskan apa yang terbaik untuk kueri. Anda adalah bosnya dalam hal gabungan fisik untuk digunakan.

Sekarang berhenti, di sana. Sebenarnya, pengoptimal kueri biasanya memilih gabungan fisik terbaik untuk kueri Anda. Jika Anda tidak tahu apa yang Anda lakukan, jangan gunakan petunjuk bergabung.

Petunjuk yang mungkin dapat Anda tentukan adalah LOOP, MERGE, HASH, atau REMOTE.

Saya belum pernah menggunakan petunjuk bergabung, tapi begini sintaksnya:


<join type> <join hint> JOIN <table source> [<alias>] ON <join condition>

Semua Tentang INNER JOIN

INNER JOIN mengembalikan baris dengan catatan yang cocok di kedua tabel, berdasarkan kondisi. Ini juga merupakan gabungan default jika Anda tidak menentukan kata kunci INNER:

Seperti yang Anda lihat, mencocokkan baris dari Tabel1 dan Tabel2 dikembalikan menggunakan Key1 sebagai syarat bergabung. Tabel1 catatan memiliki Key1 ='C' dikecualikan karena tidak ada catatan yang cocok di Tabel2 .

Setiap kali saya membuat kueri, pilihan pertama saya adalah INNER JOIN. OUTER JOIN datang ketika persyaratan hanya menentukannya.

Sintaks INNER JOIN

Ada dua sintaks INNER JOIN yang didukung di T-SQL:SQL-92 dan SQL-89.

SQL-92 INNER GABUNG

FROM <table source1> [<alias1>]
INNER JOIN <table source2> [<alias2>] ON <join condition1>
[INNER JOIN <table source3> [<alias3>] ON <join condition2>
 INNER JOIN <table sourceN> [<aliasN>] ON <join conditionN>]
[WHERE <condition>]

SQL-89 INNER GABUNG

FROM <table source1> [alias1], <table source2> [alias2] [, <table source3> [alias3], <table sourceN> [aliasN]]
WHERE (<join condition1>)
[AND (<join condition2>)
AND (<join condition3>)
AND (<join conditionN>)]

Sintaks INNER JOIN mana yang Lebih Baik?

Sintaks join pertama yang saya pelajari adalah SQL-89. Ketika SQL-92 akhirnya tiba, saya pikir itu terlalu panjang. Saya juga berpikir karena outputnya sama, mengapa repot-repot mengetik lebih banyak kata kunci? Seorang desainer kueri grafis memiliki kode yang dihasilkan SQL-92, dan saya mengubahnya kembali ke SQL-89. Tapi hari ini, saya lebih suka SQL-92 bahkan jika saya harus mengetik lebih banyak. Inilah alasannya:

  • Niat jenis joinnya jelas. Orang berikutnya yang akan memelihara kode saya akan tahu apa yang dimaksud dalam kueri.
  • Melupakan kondisi gabungan dalam sintaks SQL-92 akan memicu kesalahan. Sementara itu, melupakan kondisi join di SQL-89 akan diperlakukan sebagai CROSS JOIN. Jika yang saya maksud adalah INNER atau OUTER join, itu akan menjadi bug logika yang tidak terlihat sampai pengguna mengeluh.
  • Alat baru lebih condong ke SQL-92. Jika saya pernah menggunakan desainer kueri grafis lagi, saya tidak perlu mengubahnya ke SQL-89. Saya tidak lagi keras kepala, jadi detak jantung saya kembali normal. Semangat untuk saya.

Alasan di atas adalah milik saya. Anda mungkin memiliki alasan mengapa Anda lebih memilih SQL-92 atau mengapa Anda membencinya. Aku ingin tahu apa alasan-alasan itu. Beri tahu saya di bagian Komentar di bawah.

Tapi kita tidak bisa mengakhiri artikel ini tanpa contoh dan penjelasan.

10 Contoh INNER JOIN

1. Bergabung dengan 2 Tabel

Berikut ini contoh 2 tabel yang digabungkan menggunakan INNER JOIN dalam sintaks SQL-92.

-- Display Vests, Helmets, and Light products

USE AdventureWorks
GO

SELECT
 p.ProductID
,P.Name AS [Product]
,ps.ProductSubcategoryID
,ps.Name AS [ProductSubCategory]
FROM Production.Product p
INNER JOIN Production.ProductSubcategory ps ON P.ProductSubcategoryID = ps.ProductSubcategoryID
WHERE P.ProductSubcategoryID IN (25, 31, 33);  -- for vest, helmet, and light 
                                            -- product subcategories

Anda hanya menentukan kolom yang Anda butuhkan. Dalam contoh di atas, 4 kolom ditentukan. Saya tahu ini terlalu panjang dari SELECT * tetapi ingatlah ini:ini adalah praktik terbaik.

Perhatikan juga penggunaan alias tabel. Baik Produk dan Subkategori Produk tabel memiliki kolom bernama [Nama ]. Jika Anda tidak menentukan alias, kesalahan akan dipicu.

Sementara itu, berikut sintaks SQL-89 yang setara:

-- Display Vests, Helmets, and Light products

USE AdventureWorks
GO

SELECT
 p.ProductID
,P.Name AS [Product]
,ps.ProductSubcategoryID
,ps.Name AS [ProductSubCategory]
FROM Production.Product p, Production.ProductSubcategory ps 
WHERE P.ProductSubcategoryID = ps.ProductSubcategoryID
AND P.ProductSubcategoryID IN (25, 31, 33);

Mereka sama kecuali untuk kondisi join yang dicampur dalam klausa WHERE dengan kata kunci AND. Tetapi di bawah tenda, apakah mereka benar-benar sama? Mari kita periksa kumpulan hasil, STATISTICS IO, dan Execution Plan.

Lihat kumpulan hasil dari 9 catatan:

Bukan hanya hasil, tetapi sumber daya yang dibutuhkan oleh SQL Server juga sama.

Lihat bacaan logisnya:

Terakhir, Rencana Eksekusi mengungkapkan rencana kueri yang sama untuk kedua kueri saat QueryPlanHashes adalah sama. Perhatikan juga operasi yang disorot dalam diagram:

Berdasarkan temuan, pemrosesan query SQL Server adalah sama, apakah itu SQL-92 atau SQL-89. Tapi seperti yang saya katakan, kejelasan dalam SQL-92 jauh lebih baik bagi saya.

Gambar 7 juga menunjukkan Gabung Loop Bersarang yang digunakan dalam rencana. Mengapa? Kumpulan hasil kecil.

2. Bergabung dengan Beberapa Tabel

Lihat kueri di bawah ini menggunakan 3 tabel gabungan.

-- Get the total number of orders per Product Category
USE AdventureWorks
GO

SELECT
 ps.Name AS ProductSubcategory
,SUM(sod.OrderQty) AS TotalOrders
FROM Production.Product p
INNER JOIN Sales.SalesOrderDetail sod ON P.ProductID = sod.ProductID
INNER JOIN Sales.SalesOrderHeader soh ON sod.SalesOrderID = soh.SalesOrderID
INNER JOIN Production.ProductSubcategory ps ON p.ProductSubcategoryID = ps.ProductSubcategoryID
WHERE soh.OrderDate BETWEEN '1/1/2014' AND '12/31/2014'
AND p.ProductSubcategoryID IN (1,2)
GROUP BY ps.Name
HAVING ps.Name IN ('Mountain Bikes', 'Road Bikes')

3. Gabungan Gabungan

Anda juga dapat menggabungkan 2 tabel menggunakan 2 kunci untuk menghubungkannya. Lihat contoh di bawah ini. Ini menggunakan 2 kondisi bergabung dengan operator AND.

SELECT
 a.column1
,b.column1
,b.column2
FROM Table1 a
INNER JOIN Table2 b ON a.column1 = b.column1 AND a.column2 = b.column2

4. INNER JOIN Menggunakan Penggabungan Fisik Loop Bersarang

Pada contoh di bawah, Produk tabel memiliki 9 catatan – satu set kecil. Tabel yang digabungkan adalah SalesOrderDetail - satu set besar. Query Optimizer akan menggunakan Nested Loop Join, seperti yang ditunjukkan pada Gambar 8.

USE AdventureWorks
GO

SELECT
 sod.SalesOrderDetailID
,sod.ProductID
,P.Name
,P.ProductNumber
,sod.OrderQty
FROM Sales.SalesOrderDetail sod
INNER JOIN Production.Product p ON sod.ProductID = p.ProductID
WHERE P.ProductSubcategoryID IN(25, 31, 33);

5. INNER JOIN Menggunakan Gabung Gabung Fisik

Contoh di bawah ini menggunakan Gabung Gabung karena kedua tabel input diurutkan berdasarkan SalesOrderID.

SELECT
 soh.SalesOrderID
,soh.OrderDate
,sod.SalesOrderDetailID
,sod.ProductID
,sod.LineTotal
FROM Sales.SalesOrderHeader soh
INNER JOIN sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID

6. INNER JOIN Menggunakan Hash Physical Join

Contoh berikut akan menggunakan Hash Join:

SELECT
 s.Name AS Store
,SUM(soh.TotalDue) AS TotalSales
FROM Sales.SalesOrderHeader soh
INNER JOIN Sales.Store s ON soh.SalesPersonID = s.SalesPersonID
GROUP BY s.Name

7. INNER JOIN Menggunakan Adaptive Physical Join

Pada contoh di bawah ini, SalesPerson tabel memiliki Indeks ColumnStore Non-cluster di TerritoryID kolom. Pengoptimal Kueri memutuskan Penggabungan Loop Bersarang, seperti yang ditunjukkan pada Gambar 11.

SELECT
sp.BusinessEntityID
,sp.SalesQuota
,st.Name AS Territory
FROM Sales.SalesPerson sp
INNER JOIN Sales.SalesTerritory st ON sp.TerritoryID = st.TerritoryID
WHERE sp.TerritoryID BETWEEN 1 AND 5

8. Dua Cara untuk Menulis Ulang Subquery ke INNER JOIN

Pertimbangkan pernyataan ini dengan subquery bersarang:

SELECT [SalesOrderID], [OrderDate], [ShipDate], [CustomerID]
FROM Sales.SalesOrderHeader 
WHERE [CustomerID] IN (SELECT [CustomerID] FROM Sales.Customer
			WHERE PersonID IN (SELECT BusinessEntityID FROM Person.Person
                                          WHERE lastname LIKE N'I%' AND PersonType='SC'))

Hasil yang sama bisa keluar jika Anda mengubahnya menjadi INNER JOIN, seperti di bawah ini:

SELECT o.[SalesOrderID], o.[OrderDate], o.[ShipDate], o.[CustomerID]
FROM Sales.SalesOrderHeader o
INNER JOIN Sales.Customer c on o.CustomerID = c.CustomerID
INNER JOIN Person.Person p ON c.PersonID = p.BusinessEntityID
WHERE p.PersonType = 'SC'
AND p.lastname LIKE N'I%'

Cara lain untuk menulis ulang adalah dengan menggunakan tabel turunan sebagai sumber tabel untuk INNER JOIN:

SELECT o.[SalesOrderID], o.[OrderDate], o.[ShipDate], o.[CustomerID]
FROM Sales.SalesOrderHeader o
INNER JOIN (SELECT c.CustomerID, P.PersonType, P.LastName
            FROM Sales.Customer c
            INNER JOIN Person.Person p ON c.PersonID = P.BusinessEntityID
	      WHERE p.PersonType = 'SC'
	        AND p.LastName LIKE N'I%') AS q ON o.CustomerID = q.CustomerID

Ketiga kueri menghasilkan 48 record yang sama.

9. Menggunakan Petunjuk Bergabung

Kueri berikut menggunakan Nested Loop:

SELECT
 sod.SalesOrderDetailID
,sod.ProductID
,P.Name
,P.ProductNumber
,sod.OrderQty
FROM Sales.SalesOrderDetail sod
INNER JOIN Production.Product p ON sod.ProductID = p.ProductID
WHERE P.ProductSubcategoryID IN(25, 31, 33);

Jika Anda ingin memaksanya untuk bergabung dengan Hash, inilah yang terjadi:

SELECT
 sod.SalesOrderDetailID
,sod.ProductID
,P.Name
,P.ProductNumber
,sod.OrderQty
FROM Sales.SalesOrderDetail sod
INNER HASH JOIN Production.Product p ON sod.ProductID = p.ProductID
WHERE P.ProductSubcategoryID IN(25, 31, 33);

Namun, perhatikan bahwa STATISTICS IO menunjukkan bahwa kinerja akan menjadi buruk saat Anda memaksanya untuk bergabung dengan Hash.

Sedangkan query di bawah ini menggunakan Merge Join:

SELECT
 soh.SalesOrderID
,soh.OrderDate
,sod.SalesOrderDetailID
,sod.ProductID
,sod.LineTotal
FROM Sales.SalesOrderHeader soh
INNER JOIN sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID

Begini jadinya jika Anda memaksanya ke Nested Loop:

SELECT
 soh.SalesOrderID
,soh.OrderDate
,sod.SalesOrderDetailID
,sod.ProductID
,sod.LineTotal
FROM Sales.SalesOrderHeader soh
INNER LOOP JOIN sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID

Setelah memeriksa STATISTICS IO dari keduanya, memaksanya ke Nested Loop memerlukan lebih banyak sumber daya untuk memproses kueri:

Jadi, menggunakan petunjuk bergabung harus menjadi pilihan terakhir Anda saat mengutak-atik kinerja. Biarkan SQL Server Anda menanganinya untuk Anda.

10. Menggunakan INNER JOIN di UPDATE

Anda juga dapat menggunakan INNER JOIN dalam pernyataan UPDATE. Ini contohnya:

UPDATE Sales.SalesOrderHeader
SET ShipDate = getdate() 
FROM Sales.SalesOrderHeader o
INNER JOIN Sales.Customer c on o.CustomerID = c.CustomerID
INNER JOIN Person.Person p ON c.PersonID = p.BusinessEntityID
WHERE p.PersonType = 'SC'

Karena dimungkinkan untuk menggunakan gabungan dalam UPDATE, mengapa tidak mencobanya menggunakan DELETE dan INSERT?

SQL Join dan INNER JOIN Takeaways

Jadi, apa hebatnya bergabung dengan SQL?

  • Sebuah SQL JOIN menggabungkan record dari 2 tabel atau lebih untuk membentuk satu kumpulan hasil.
  • Ada jenis gabungan dalam SQL:INNER, OUTER, dan CROSS.
  • Sebagai pengembang atau administrator, Anda yang memutuskan operasi logis atau jenis gabungan mana yang akan digunakan untuk kebutuhan Anda.
  • Di sisi lain, Pengoptimal Kueri memutuskan operator gabungan fisik terbaik untuk digunakan. Itu bisa berupa Nested Loop, Merge, Hash, atau Adaptive.
  • Anda dapat menggunakan petunjuk bergabung untuk memaksa gabungan fisik apa yang akan digunakan, tetapi itu harus menjadi pilihan terakhir Anda. Dalam kebanyakan kasus, lebih baik biarkan SQL Server Anda menanganinya.
  • Mengetahui operator gabungan fisik juga membantu Anda dalam menyetel kinerja kueri.
  • Selain itu, subkueri dapat ditulis ulang menggunakan gabungan.

Sementara itu, postingan ini menunjukkan 10 contoh INNER JOIN. Ini bukan hanya kode sampel. Beberapa di antaranya juga mencakup pemeriksaan cara kerja kode dari dalam ke luar. Ini bukan hanya untuk membantu Anda membuat kode tetapi untuk membantu Anda memperhatikan kinerja. Pada akhirnya, hasilnya tidak hanya harus benar tetapi juga disampaikan dengan cepat.

Kami belum selesai. Artikel selanjutnya akan membahas OUTER JOINS. Pantau terus.

Lihat juga

SQL Joins memungkinkan Anda mengambil dan menggabungkan data dari lebih dari satu tabel. Tonton video ini untuk mempelajari lebih lanjut tentang SQL Joins.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Pivoting, Unpivoting, dan Pemisahan Kolom di Power BI Query Editor

  2. Bendera Jejak 2389 dan Penaksir Kardinalitas baru

  3. KENDALA SQL

  4. Cara Memuat dan Mengelola Data dalam Microsoft Power BI

  5. Membuat Rencana Pemeliharaan Basis Data