web-dev-qa-db-ja.com

テーブルのデータに基づいて条件付きJOINまたは条件付きSELECTを実行できますか?

EAVが最良の選択であるという問題があると思います。

私は次のようにテーブルを計画しています。

マザーボード

motherboard_id | model_name
int            | varchar

例:

motherboard_id | model_name
----------------------------
1              | Asus Rampage
2              | Intel 3X
3              | Gigabit 22P

属性

attribute_id  | attribute_name | attribute_type
int           | varchar        | enum('str','int','float')

例:

attribute_id   | attribute_name| attribute_type
-------------------------------------------------
1              | form_factor   | int
2              | max_ram       | int
3              | ram_type      | str
4              | weight        | float
5              | CPU_socket    | str
6              | PCH           | str

マザーボード_attribute_int

attribute_id  | motherboard_id | value
int           | int            | int

例:

attribute_id   | motherboard_id | value
-----------------------------------------
1              | 1              | 1
2              | 1              | 16384
1              | 2              | 1
2              | 2              | 32,768
1              | 3              | 2
2              | 3              | 8192

マザーボード_attribute_str

attribute_id  | motherboard_id | value
int           | int            | varchar

例:

attribute_id   | motherboard_id | value
--------------------------------------------
3              | 1              | DDR3
5              | 1              | LGA2011
6              | 1              | Intel P55
3              | 2              | DDR3
5              | 2              | LGA3011
3              | 3              | DDR2
5              | 3              | Socket 2

マザーボード_attribute_float

attribute_id  | motherboard_id | value
int           | int            | float

例:

attribute_id   | motherboard_id | value
------------------------------------------
4              | 1              | 250.2
4              | 2              | 250.2
4              | 2              | 110.5

すべての属性についてクエリを実行する必要があります(WHERE句を使用)。例えば ​​-

重量が150gを超え、max_ramが16Mを超えるすべてのマザーボードを検索します

したがって、属性テーブルをクエリして、intとweightのmax_ramがfloatであることを確認する必要があります。したがって、motherboardmotherboard_attribute_intおよびmotherboard_attribute_floatと結合する必要があります

これを行う方法はありますか?

この種のデータをより適切に提供する代替データベース設計はありますか?

6
Lord Loh.

本当に必要なのは、null許容フィールドでいっぱいのテーブルです。EAVを正しく取得するのは困難です。EAVでは、文字通り6列ではなく3列が必要です。現時点では、必要に応じてnull許容列を追加し続ける方がはるかに簡単です。

では、20列または30列のテーブルがある場合、パフォーマンスとスケーラビリティの問題は発生しないはずですか? 30列のテーブルを作成すると、何がトレードオフになりますか?

何をトレードオフしていますか?本当に何もありません。パフォーマンスとスケーラビリティの問題は、従来のワイドテーブル形式よりもEAV形式で解釈および診断するのがはるかに困難です。実際には、必要なものをすばやく見つけるために適切なインデックスが必要なだけのnull値がたくさんあるテーブルになります。これは、EAVを使用するよりもはるかに簡単です。

データ型ごとに1つのEAVテーブルを実行することは、パフォーマンスとメンテナンスの観点から、前に説明した5列以上の設計と同じくらい恐ろしいことです。あなたは本当にこれをしたくありません。本当に、1つの幅の広いテーブルに多くのNULL可能列を追加したいだけです。あなたは自分の足を撃ち、始める前に包帯を巻く方法を私たちに尋ねています。 EAVは、モデルがどのように機能するかを理解していないこともあり、現時点で必要なデザインパターンではありません。ビジネスデータをモデル化してから、データベースをモデル化します。

あなたの場合、ベンダー、ボード名/モデル番号などのマザーボード用のテーブルが必要です。以下の簡単なテーブルをモデル化しました。次に、EAVをこのテーブルとともに使用して、「ドライバーのダウンロード用のリンク」など、ほとんど必要とされないものをモデル化します。メインテーブルは詳細を検索するものであり、EAVはUIにセカンダリタブを表示するときにのみ必要な詳細であると考えてください。

create table motherboards (
   id bigint not null auto_increment
 , vendor_name varchar(100) not null -- would also be good as a lookup column to another table, making this an int or bigint instead
 , board_name varchar(100) not null
 , revision_number varchar(100) null
 , cpu_socket_type not null -- can be an int lookup to another table or a text field, I leave this to you based on the schema you want, but either is acceptable, as is an int with an in-app enum lookup
 , cpu_socket_count int not null default 1
 , ram_socket_type not null -- again, can be one of so many values, you decide the best type of storage
 , ram_socket_count tinyint not null default 1 -- here's where things get tricky, it's possible on some systems (enterprise grade) to have different RAM sockets for different reasons, but we skip that because that's a lot of detail. Wait till you have to cross that bridge, mkay?
 , northbridge_chipset varchar(100) not null -- this makes the most sense to me, but see the cpu_socket_type comment. There are a handful of common ones, so text may be easier to deal with. 
 , southbridge_chipset varchar(100) null -- see above

-- This is now the additional details for others
 , rear_port_usb tinyint not null default 2
 , usb_headers tinyint not null default 0
 , upc_number varchar(20) null
 , pcie_socket_count tinyint not null default 0
 , pcie_x2_socket_count tinyint not null default 0
 , pcie_x4_socket_count tinyint not null default 0
 , pcie_x8_socket_count tinyint not null default 0
 , pcie_x16_socket_count tinyint not null default 0
 , sata_headers_count tinyint not null default 0
 , pci_socket_count tinyint not null default 0
 , isa_socket_count tinyint not null default 0
 , rear_port_matrix -- some set of fields to indicate what is on the back panel where people can have access. I would probably either make up a standard "dictionary" of these and do it like an enum/lookup table, or list one per port. Where do you put parallel ports on this lookup list? How many USB are exposed via the backplate? How many USB are exposed on headers on the motherboard?
)

create table motherboards_details (
   id bigint not null (fk back to motherboards)
 , name varchar(100) not null
 , value varchar(100) not null
 , create_date datetime not null default CURRENT_TIMESTAMP -- always good to have for later tracking
)

以上です。これ以上EAVはありません。 floatまたはintとして使用する必要がある場合は、アプリケーションでそれを行います。

ソケットビットをすべてEAVに移動するなど、詳細を追跡するためにEAVを使用することに夢中になっている場合は、他にもいくつか提案がありますが、私が言ったよりもはるかに面倒になると言ったら、私を信じてください君は。この形式では、(ピッカーUIのように)必要な詳細を検索でき、非常に大きなテーブルを取得したら、一般的に検索される機能のインデックスを作成できます。私が提案する唯一のインデックスは、ボード名、ソケットのタイプとカウント、およびルックアップ用のIDです。システムに実際のデータをロードした後、他のすべてのインデックスを作成します。

EAVモデルは現在このビジネスモデルに実際には適合していないため、実際のEAVスキーマの意図を確認せずに、上記で概説したスタイルからアプローチし、列幅を無視することをお勧めします。

上で概説したアプローチは、これまでのところレコードあたり約500バイトであり、これは比較的小さいものです。インデックスだけを維持するのは難しいでしょう。

これが問題設計へのアプローチを再考するのに役立つことを願っています。私たちはいつもコミュニティとして、詳細を具体化するのを喜んでお手伝いします。

4
jcolebrand