Struktur basis data inventaris ketika item persediaan memiliki atribut yang berbeda-beda

10

Saya sedang membangun database inventaris untuk menyimpan informasi perangkat keras perusahaan. Perangkat basis data melacak jangkauan dari workstation, laptop, switch, router, ponsel, dll. Saya menggunakan nomor seri perangkat sebagai kunci utama. Masalah yang saya alami adalah bahwa atribut lain untuk perangkat ini bervariasi dan saya tidak ingin memiliki bidang dalam tabel inventaris yang tidak terkait dengan perangkat lain. Di bawah ini adalah tautan ke ERD bagian dari basis data (beberapa hubungan FK tidak diperlihatkan). Saya mencoba mengaturnya, misalnya, jadi perangkat dengan tipe perangkat workstation tidak dapat dimasukkan ke dalam tabel ponsel. Ini tampaknya membutuhkan penggunaan banyak pemicu untuk memvalidasi jenis perangkat atau kelas, dan tabel baru kapan saja perangkat yang berbeda dengan atribut yang berbeda akan dilacak;

ERD1

Saya melihat ke pengaturan tabel atribut yang dapat dipetakan ke nomor seri, tetapi itu akan memungkinkan atribut yang tidak berlaku untuk jenis perangkat untuk ditugaskan ke perangkat, misalnya, seseorang dapat menetapkan atribut nomor telepon ke workstation jika mereka mau . Saya menemukan penjelasan di situs ini yang memberikan struktur berikut:

Contoh Widget ERD

Struktur ini akan bekerja dengan baik jika semua atribut berlaku untuk barang yang saya simpan. Misalnya jika database hanya menyimpan ponsel, atributnya bisa seperti touchscreen, trackpad, keyboard, 4G, 3G ... apa pun. Dalam hal itu, semuanya berlaku untuk telepon. Basis data saya akan memiliki atribut seperti nama host, tipe sirkuit, nomor telepon, yang hanya berlaku untuk jenis perangkat tertentu.

Saya ingin mengaturnya sehingga hanya atribut yang berlaku untuk jenis perangkat tertentu yang dapat ditetapkan ke perangkat jenis itu. Adakah saran tentang cara mengatur basis data ini? Saya tidak yakin apakah ini penggunaan yang tepat dari hubungan satu-ke-satu, atau apakah ada cara yang lebih baik untuk melakukan ini. Terima kasih sebelumnya telah meluangkan waktu untuk melihat ini.

Berikut adalah beberapa utas lainnya yang saya baca. Mereka memberi saya wawasan yang bagus, tetapi saya pikir itu tidak berlaku:

/programming/9335548/how-to-structure-database-for-inventory-of-unlike-items

/programming/1249632/database-structure-for-items-with-varying-attributes

/programming/5559587/product-inventory-with-multiple-attributes

/programming/6613802/question-about-setting-up-inventory-database

/programming/514111/how-to-best-represent-items-with-variable-of-attributes-in-a-database

TheSecretSquad
sumber

Jawaban:

6

Supertype / Subtype

Bagaimana kalau melihat pola supertipe / subtipe? Kolom umum masuk dalam tabel induk. Setiap tipe berbeda memiliki tabelnya sendiri dengan ID induk sebagai PK-nya sendiri dan berisi kolom unik yang tidak umum untuk semua subtipe. Anda bisa memasukkan kolom tipe dalam tabel induk dan anak-anak untuk memastikan setiap perangkat tidak boleh lebih dari satu subtipe. Buat FK antara anak-anak dan orang tua di (ItemID, ItemTypeID). Anda bisa menggunakan FK untuk tabel supertype atau subtype untuk menjaga integritas yang diinginkan di tempat lain. Misalnya, jika ItemID jenis apa pun diizinkan, buat FK ke tabel induk. Jika hanya SubItemType1 yang dapat direferensikan, buat FK ke tabel itu. Saya akan meninggalkan TypeID dari tabel referensi.

Penamaan

Ketika berbicara soal penamaan, Anda memiliki dua pilihan seperti yang saya lihat (karena pilihan ketiga "ID" saja dalam benak saya adalah anti-pola yang kuat). Panggil kunci subtipe ItemID seperti di tabel induk, atau sebut saja nama subtipe seperti DoohickeyID. Setelah beberapa pemikiran dan beberapa pengalaman dengan ini, saya menganjurkan menyebutnya DoohickeyID. Alasan untuk ini adalah bahwa meskipun mungkin ada kebingungan tentang tabel subtipe benar-benar menyamar yang mengandung Item (bukan Doohickeys), itu adalah negatif kecil dibandingkan dengan ketika Anda membuat FK ke tabel Doohickey dan nama kolom tidak pertandingan!

Ke EAV atau tidak ke EAV - Pengalaman saya dengan basis data EAV

Jika EAV adalah apa yang benar-benar harus Anda lakukan, maka itulah yang harus Anda lakukan. Tetapi bagaimana jika itu bukan apa yang harus Anda lakukan?

Saya membangun basis data EAV yang digunakan dalam bisnis. Alhamdulillah, set datanya kecil (meskipun ada lusinan jenis item) sehingga kinerjanya tidak buruk. Tetapi akan buruk jika database memiliki lebih dari beberapa ribu item di dalamnya! Selain itu, tabelnya begitu SULIT untuk kueri. Pengalaman ini telah membuat saya benar-benar ingin menghindari basis data EAV di masa depan jika memungkinkan.

Sekarang, di basis data saya, saya membuat prosedur tersimpan yang secara otomatis membangun tampilan PIVOT untuk setiap subtipe yang ada. Saya bisa saja meminta dari AutoDoohickey. Metadata saya tentang subtipe memiliki kolom "ShortName" yang berisi nama objek-aman yang cocok untuk digunakan dalam nama tampilan. Saya bahkan membuat tampilan dapat diperbarui! Sayangnya, Anda tidak dapat memperbaruinya saat bergabung, tetapi Anda BISA memasukkannya ke baris yang sudah ada, yang akan dikonversi menjadi UPDATE. Sayangnya, Anda tidak dapat memperbarui hanya beberapa kolom, karena tidak ada cara untuk menunjukkan ke VIEW kolom mana yang ingin Anda perbarui dengan proses konversi INSERT-to-UPDATE: nilai NULL terlihat seperti "perbarui kolom ini ke NULL" walaupun Anda ingin menunjukkan "Jangan perbarui kolom ini sama sekali."

Terlepas dari semua dekorasi ini untuk membuat basis data EAV lebih mudah digunakan, saya masih tidak menggunakan pandangan ini dalam kueri paling normal karena ini adalah PERLAHAN. Kondisi kueri bukanlah predikat yang didorong sepenuhnya kembali ke Valuetabel, sehingga harus membuat kumpulan hasil antara semua item dari jenis tampilan itu sebelum memfilter. Aduh. Jadi saya punya banyak, banyak pertanyaan dengan banyak, banyak gabungan, masing-masing keluar untuk mendapatkan nilai yang berbeda dan seterusnya. Mereka tampil relatif baik, tetapi aduh! Ini sebuah contoh. SP yang menciptakan ini (dan pemicu pembaruannya) adalah salah satu binatang buas raksasa, dan saya bangga akan hal itu, tetapi ini bukan sesuatu yang ingin Anda coba pertahankan.

CREATE VIEW [dbo].[AutoModule]
AS
--This view is automatically generated by the stored procedure AutoViewCreate
SELECT
   ElementID,
   ElementTypeID,
   Convert(nvarchar(160), [3]) [FullName],
   Convert(nvarchar(1024), [435]) [Descr],
   Convert(nvarchar(255), [439]) [Comment],
   Convert(bit, [438]) [MissionCritical],
   Convert(int, [464]) [SupportGroup],
   Convert(int, [461]) [SupportHours],
   Convert(nvarchar(40), [4]) [Ver],
   Convert(bit, [28744]) [UsesJava],
   Convert(nvarchar(256), [28745]) [JavaVersions],
   Convert(bit, [28746]) [UsesIE],
   Convert(nvarchar(256), [28747]) [IEVersions],
   Convert(bit, [28748]) [UsesAcrobat],
   Convert(nvarchar(256), [28749]) [AcrobatVersions],
   Convert(bit, [28794]) [UsesDotNet],
   Convert(nvarchar(256), [28795]) [DotNetVersions],
   Convert(bit, [512]) [WebApplication],
   Convert(nvarchar(10), [433]) [IFAbbrev],
   Convert(int, [437]) [DataID],
   Convert(nvarchar(1000), [463]) [Notes],
   Convert(nvarchar(512), [523]) [DataDescription],
   Convert(nvarchar(256), [27991]) [SpecialNote],
   Convert(bit, [28932]) [Inactive],
   Convert(int, [29992]) [PatchTestedBy]
FROM (
   SELECT
      E.ElementID + 0 ElementID,
      E.ElementTypeID,
      V.AttrID,
      V.Value
   FROM
      dbo.Element E
      LEFT JOIN dbo.Value V ON E.ElementID = V.ElementID
   WHERE
      EXISTS (
         SELECT *
         FROM dbo.LayoutUsage L
         WHERE
            E.ElementTypeID = L.ElementTypeID
            AND L.AttrLayoutID = 7
      )
) X
PIVOT (
   Max(Value)
   FOR AttrID IN ([3], [435], [439], [438], [464], [461], [4], [28744], [28745], [28746], [28747], [28748], [28749], [28794], [28795], [512], [433], [437], [463], [523], [27991], [28932], [29992])
) P;

Berikut jenis lain dari tampilan yang dibuat secara otomatis yang dibuat oleh prosedur tersimpan lain dari metadata khusus untuk membantu menemukan hubungan antara item yang dapat memiliki beberapa jalur di antara mereka (Khususnya: Module-> Server, Module-> Cluster-> Server, Module-> DBMS- > Server, Modul-> DBMS-> Cluster-> Server):

CREATE VIEW [dbo].[Link_Module_Server]
AS
-- This view is automatically generated by the stored procedure LinkViewCreate
SELECT
   ModuleID = A.ElementID,
   ServerID = B.ElementID
FROM
   Element A
   INNER JOIN Element B
      ON EXISTS (
         SELECT *
         FROM
            dbo.Element R1
         WHERE
            A.ElementID = R1.ElementID1
            AND B.ElementID = R1.ElementID2
            AND R1.ElementTypeID = 38
      ) OR EXISTS (
         SELECT *
         FROM
            dbo.Element R1
            INNER JOIN dbo.Element R2 ON R1.ElementID2 = R2.ElementID1
         WHERE
            A.ElementID = R1.ElementID1
            AND R1.ElementTypeID = 40
            AND B.ElementID = R2.ElementID2
            AND R2.ElementTypeID = 38
      ) OR EXISTS (
         SELECT *
         FROM
            dbo.Element R1
            INNER JOIN dbo.Element R2 ON R1.ElementID2 = R2.ElementID1
         WHERE
            A.ElementID = R1.ElementID1
            AND R1.ElementTypeID = 38
            AND B.ElementID = R2.ElementID2
            AND R2.ElementTypeID = 3122
      ) OR EXISTS (
         SELECT *
         FROM
            dbo.Element R1
            INNER JOIN dbo.Element R2 ON R1.ElementID2 = R2.ElementID1
            INNER JOIN dbo.Element C2 ON R2.ElementID2 = C2.ElementID
            INNER JOIN dbo.Element R3 ON R2.ElementID2 = R3.ElementID1
         WHERE
            A.ElementID = R1.ElementID1
            AND R1.ElementTypeID = 40
            AND C2.ElementTypeID = 3080
            AND R2.ElementTypeID = 38
            AND B.ElementID = R3.ElementID2
            AND R3.ElementTypeID = 3122
      )
WHERE
   A.ElementTypeID = 9
   AND B.ElementTypeID = 17

Pendekatan Hibrida

Jika Anda HARUS memiliki beberapa aspek dinamis dari basis data EAV, Anda dapat mempertimbangkan membuat metadata seolah-olah Anda memiliki basis data seperti itu, tetapi sebaliknya benar-benar menggunakan pola desain supertype / subtipe. Ya, Anda harus membuat tabel baru, dan menambah dan menghapus dan memodifikasi kolom. Tetapi dengan pra-pemrosesan yang tepat (seperti yang saya lakukan dengan tampilan otomatis database EAV saya) Anda bisa memiliki objek seperti tabel nyata untuk bekerja dengannya. Hanya saja, mereka tidak akan sebesar saya dan pengoptimal kueri dapat predikat push down ke tabel dasar (baca: berkinerja baik dengan mereka). Hanya akan ada satu gabungan antara tabel supertype dan tabel subtype. Aplikasi Anda dapat diatur untuk membaca metadata untuk menemukan apa yang seharusnya dilakukan (atau dapat menggunakan tampilan yang dibuat secara otomatis dalam beberapa kasus).

Atau, jika Anda memiliki satu set subtipe multi-level, hanya beberapa yang bergabung. Maksud saya multi-level ketika beberapa subtipe berbagi kolom umum, tetapi tidak semua, Anda bisa memiliki tabel subtipe untuk mereka yang itu sendiri merupakan supertipe dari beberapa tabel lainnya. Misalnya, jika Anda menyimpan informasi tentang Server, Router, dan Printer, subtipe "Perangkat IP" antara bisa masuk akal.

Saya akan memberikan peringatan bahwa saya belum membuat basis data yang didekorasi dengan supertipe / subtipe hibrid EAV seperti yang saya sarankan di sini untuk dicoba di dunia nyata. Tetapi masalah yang saya alami dengan EAV tidak kecil, dan melakukan sesuatu mungkin mutlak harus jika database Anda akan besar dan Anda ingin kinerja yang baik tanpa beberapa perangkat keras raksasa yang mahal.

Menurut pendapat saya, waktu yang dihabiskan mengotomatiskan penggunaan / pembuatan / modifikasi tabel subtipe nyata pada akhirnya akan menjadi yang terbaik. Berfokus pada fleksibilitas yang didorong oleh data membuat EAV terdengar sangat menarik (dan percayalah, saya suka bagaimana ketika seseorang meminta saya untuk atribut baru pada tipe elemen saya dapat menambahkannya dalam waktu sekitar 18 detik dan mereka dapat segera mulai memasukkan data di situs web. ). Tetapi fleksibilitas dapat dicapai dalam lebih dari satu cara! Pra-pemrosesan adalah cara lain untuk melakukannya. Ini adalah metode yang sangat kuat yang hanya sedikit orang gunakan, memberikan manfaat menjadi data-driven sepenuhnya tetapi kinerja hard-coded.

(Catatan: Ya pandangan-pandangan itu benar-benar diformat seperti itu dan yang PIVOT benar-benar memiliki pemicu pembaruan. :) Jika seseorang benar-benar tertarik pada detail menyakitkan yang mengerikan dari pemicu UPDATE yang panjang dan rumit, beri tahu saya dan saya akan memposting sampel untuk Anda.)

Dan Satu Ide Lagi

Masukkan semua data Anda dalam satu tabel. Berikan kolom nama umum dan kemudian gunakan kembali / disalahgunakan untuk beberapa tujuan. Buat pandangan atas ini untuk memberi mereka nama yang masuk akal. Tambahkan kolom ketika kolom tipe data yang cocok tidak digunakan tidak tersedia, dan perbarui tampilan Anda. Meskipun panjang saya tentang subtipe / supertype, ini mungkin cara terbaik.

ErikE
sumber
Saya memikirkan desain ini di mana setiap tabel subtipe memiliki PK dari induk dan bidang yang tidak umum. Saya pikir saya bisa meletakkan bidang jenis di induk dan setiap tabel subtipe dan kemudian menempatkan kendala PERIKSA pada mereka. Saya memutuskan untuk menghindari desain ini karena akan membutuhkan tabel baru kapan saja jenis perangkat baru perlu dilacak, dan banyak hubungan satu-ke-satu. Tampaknya berantakan dan tidak fleksibel. Saya menghargai masukan Anda.
TheSecretSquad
Saya membangun basis data EAV yang digunakan dalam bisnis. Alhamdulillah, set datanya kecil (meskipun ada lusinan jenis item) sehingga kinerjanya tidak buruk. Tapi itu akan terjadi jika database memiliki lebih dari beberapa ribu item di dalamnya. Pengalaman ini telah mendorong saya untuk benar-benar ingin menghindari basis data EAV di masa depan jika memungkinkan, karena mereka sangat SULIT untuk meminta.
ErikE
Juga, waktu yang dihabiskan untuk mengotomatisasi penggunaan / pembuatan / modifikasi tabel subtipe nyata, menurut pendapat saya, pada akhirnya akan menjadi yang terbaik.
ErikE
Setelah memeriksa pola EAV saya menyadari bahwa nilai untuk atribut dipaksa untuk berbagi tipe data (semua string dalam hal ini). Juga, meminta pengaturan EAV akan menjadi tugas. Supertype / subtype terlihat lebih baik. Pertanyaan saya sekarang, apakah tabel tertentu hanya memperbolehkan jenis perangkat tertentu. Apakah saya memvalidasi ini dengan meletakkan ID kelas perangkat (telepon, komputer, router) di setiap tabel dan memberikan batasan pemeriksaan pada bidang itu, atau apakah saya mengecualikan bidang itu dari tabel subtipe dan menggunakan pemicu pada masing-masingnya? Silakan lihat ERD3 untuk referensi.
TheSecretSquad
1
Untuk kueri data EAV, bukan hal yang aneh untuk membangun datamart dari tabel relasional untuk data yang ingin Anda query dan kemudian mengisi mereka menggunakan beberapa skrip. Kueri akan berjalan lebih cepat, tetapi hanya terhadap data yang Anda masukkan dalam datamart, dan penyetelannya memerlukan perencanaan yang adil.
FrustratedWithFormsDesigner
6

Dalam kasus Anda, pendekatan terbaik adalah variasi pada model Entity-Attribute-Value (EAV). Ada banyak orang yang menghindar dari EAV karena tidak membantu dalam beberapa hal dan sering disalahgunakan. Namun, EAV adalah solusi yang berfungsi dengan baik untuk kebutuhan spesifik Anda.

Variasi yang ingin Anda sertakan untuk situasi Anda adalah dengan abstrak atribut satu tingkat dari entitas Anda (yaitu item inventaris Anda). Pada dasarnya Anda ingin menentukan jenis perangkat yang memiliki daftar atribut. Kemudian Anda mendefinisikan instance perangkat yang memiliki nilai untuk masing-masing atribut yang dimiliki perangkat jenis itu.

Berikut ini sketsa ERD:

ERD

DEVICE_ATTRIBUTEberisi nilai untuk setiap jenis atribut generik. DEVICE_TYPEmendefinisikan daftar atribut umum yang berlaku untuk jenis perangkat tertentu (ini adalah TYPICAL_DEVICE_ATTRIBUTEs.

Ini memungkinkan Anda mengontrol atribut mana yang perlu diisi untuk suatu perangkat sementara membiarkan perangkat dari tipe yang berbeda memiliki daftar atribut yang berbeda. Ini juga memudahkan Anda untuk membandingkan seluruh perangkat dengan melampirkan atribut mereka satu sama lain.

Joel Brown
sumber
Ini mirip dengan apa yang direkomendasikan ssmusoke. Saya mengubah ERD saya menggunakan rekomendasinya dan sepertinya cocok dengan Anda. Jangan ragu untuk melihat RD baru di http://www.dividegraphics.com/ERD2.jpg dan berikan umpan balik.
TheSecretSquad
@reallythecrash - Anda benar, saya menyarankan pendekatan dasar yang sama dengan ssmusoke, saya hanya mengambil taktik berbeda pada jawaban saya dengan harapan membuatnya lebih mudah untuk memahami baik struktur model dan juga alasan untuk menggunakan EAV yang merupakan banyak orang (tidak adil) mencela sebagai anti-pola.
Joel Brown
Setelah beberapa penelitian saya melihat mengapa orang mungkin menganggap EAV sebagai anti-pola. Saya pikir itu sederhana untuk menyimpan data menggunakan EAV, tetapi sangat kompleks untuk query dan memelihara tipe data. Saya pikir ini adalah pola dengan tujuan yang sempit, dan harus digunakan oleh pengembang berpengalaman yang dapat menerapkannya dengan benar, yaitu, bukan saya. Saya mungkin akan memilih paradigma supertipe / subtipe.
TheSecretSquad
@ JoelBrown - perangkat lunak apa yang Anda gunakan untuk membuat sketsa diagram itu ?, terlihat keren.
Vidar
@Vidar - Saya menggunakan Visio dengan ERD smartshapes yang saya buat untuk menggunakan konvensi visual James Martin dan digambar dengan pola garis kustom yang samar. Saya menemukan ini adalah alat yang baik untuk digunakan untuk model data cepat / konsep. Ketika diagram terlalu formal, hal itu dapat membuat sebagian orang berpikir bahwa itu sudah selesai, jadi sesuatu yang samar membantu untuk mencegah orang melompat ke kesimpulan tentang seberapa kuat / selesai suatu model data.
Joel Brown
1
  1. Pendekatan keseluruhan adalah sebagai berikut:

a) Pendekatan model Nilai Entitas-Atribut-Nilai untuk menangani atribut dari berbagai perangkat ke jenis perangkat. Setiap jenis perangkat akan memiliki daftar atribut yang nilainya Anda lacak

b) Untuk setiap jenis perangkat, Anda melacak detail inventaris dengan nomor seri yang sesuai dengan satu perangkat.

  1. Jadi, Anda akan berakhir dengan tabel berikut:

a) Atribut - menentukan atribut untuk semua perangkat (apa pun yang terjadi dalam tabel ini) kolom: id, nama, deskripsi

b) Item Attributes - mendefinisikan atribut yang diperbolehkan untuk perangkat tertentu - itemid, atributid

c) Definisi Item - mendefinisikan item yang mengatakan Black Berry Torch 4500, Iphone 4S, Iphone 3S dll - id, nama, deskripsi, categoryid (jika Anda ingin menambahkan kategori seperti ponsel, switch, dll)

d) Perangkat - perangkat individual - id, itemid, inventaris, dinonaktifkan, nomor seri ... (pada dasarnya semua atribut lain untuk suatu perangkat)

Jika Anda ingin melacak informasi lain tentang transkasi perangkat maka Anda dapat menambahkan lebih banyak tabel yang tertaut ke perangkat yang Anda butuhkan.

Stephen Senkomago Musoke
sumber
Terima kasih atas masukannya. Ini sejalan dengan apa yang saya cari, saya hanya tidak tahu bagaimana melakukannya. Saya mengubah ERD saya untuk mencerminkan spesifikasi Anda. Sepertinya itu membutuhkan lebih banyak pekerjaan untuk memasukkan semua atribut yang diperbolehkan untuk setiap jenis perangkat, tetapi juga sepertinya menawarkan fleksibilitas maksimum. Saya akan membuat prototipe kecil untuk melihat apakah itu berfungsi seperti yang saya kira. Terima kasih lagi. Saya mengunggah ERD dengan perubahan jika Anda ingin melihatnya dan memberi tahu saya jika saya berada di jalur yang benar. http://www.dividegraphics.com/ERD2.jpg
TheSecretSquad
Ya, Anda berada di jalur yang benar.
Stephen Senkomago Musoke
EAV akan menawarkan banyak fleksibilitas, tetapi Anda juga memiliki lebih banyak metadata yang berkeliaran agar tetap berfungsi.
FrustratedWithFormsDesigner
@FrustratedWithFormsDesigner tampaknya tak terhindarkan ketika sistem menyimpan berbagai item, ponsel, sakelar, PC, laptop, dll. Lebih baik lebih banyak metadata daripada tabel yang akan saya katakan
Stephen Senkomago Musoke
1
@ssmusoke: Setuju, tapi saya ingin menekankan hal itu karena saya telah melihat orang gagal menyadari pentingnya metadata, dan kemudian implementasi EAV mereka menjadi mimpi buruk.
FrustratedWithFormsDesigner