3

簡単な例として、私がウィジェットを販売しているとします。私はそれらを全国的に (米国とカナダの両方で) 販売していますが、特定の地域 (1 つ以上の米国の州またはカナダの州) でしか販売できないものもあります。

この情報を保存するための優れた方法と、特定のユーザーが使用できるウィジェットをすばやく照会する方法が必要です。"US, 50 states and DC" が最も一般的な値なので、51 行を挿入したくありません。

MySQL はビットマップ インデックスをサポートしていないため、除外されています。

いくつかの組み合わせを次に示します。

  • 米国 50 州および DC
  • 米国 50 州、DC、カナダ、ただしケベックは除く。
  • 米国本土 48 州および DC
  • 米国、DC、ただしコロラド州は除く
  • 米国、DC、および領土 (プエルトリコなど)。

ユーザーは、都道府県と国に対して 1 つの値を指定します。

優れたストレージと高速マッチングを提供するスキーマを提案できますか?

ありがとう!

4

2 に答える 2

1

定義済みの値のセットを作成し、このセットをアイテムに保存する必要があります。値を使用して、一致するセットと一致するアイテムを取得します。

CREATE TABLE `valuesets` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `valueset_items` (
  `valueset_id` int(11) unsigned NOT NULL,
  `value` varchar(20) NOT NULL DEFAULT '',
  PRIMARY KEY (`valueset_id`,`value`),
  CONSTRAINT `fk_valueset_items_valueset` FOREIGN KEY (`valueset_id`) REFERENCES `valuesets` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `items` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL DEFAULT '',
  `valueset_id` int(11) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_items_valueset` (`valueset_id`),
  CONSTRAINT `fk_items_valueset` FOREIGN KEY (`valueset_id`) REFERENCES `valuesets` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

特別な値に一致するすべてのアイテムを選択するには

SELECT *
FROM items
WHERE 
  valueset_id IN ( SELECT valueset_id 
                   FROM valueset_items 
                   WHERE `value` = 'A' )

SQL フィドルのデモ

于 2012-12-22T07:36:17.140 に答える
0

これはMySQLSETタイプであり、データセットを64アイテムに抑えることができる(または、他の条件に基づいて複数のセットを使用できる)ことを前提としています。


セットの力がわからない人もいると思うので、答えを広げてみようと思いました。表の例:

CREATE TABLE `Test` (
  `setid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `setname` varchar(64) NOT NULL,
  `setstate` set('AK','AL','AR','AZ','CA','CO','CT','DC','DE','FL','GA','HI','IA','ID','IL','IN','KS','KY','LA','MA','MD','ME','MI','MN','MO','MS','MT','NC','ND','NE','NH','NJ','NM','NV','NY','OH','OK','OR','PA','RI','SC','SD','TN','TX','UT','VA','VT','WA','WI','WV','WY') NOT NULL,
  PRIMARY KEY (`setid`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;

insert into `Test` values('1','test','AZ,CA,NJ,NM,NY,VA,VT');

状態には単一のセットフィールドを使用することに注意してください。より複雑な使用には複数のセットの使用が必要になる可能性がありますが、各レコードの水平方向のqwordを少し増やすと、ルックアップテーブルに大量のレコードに簡単に到達できる多数の追加の結合操作を追加するよりも安価になる場合があります。

以下は、3つの(機能的に)同等のプルです。ビットマスクは、このデータをプルするための非常に高速な方法であることに注意してください。

SELECT * FROM Test WHERE setstate & 1000;

テスト#1では、リスト(AZ)の項目#4に対応するため、ビットマスクとして1000を使用します。これは、はるかに最速の方法です...そして、より速い結果の可能性を与えるこのデータを保存するいくつかの方法があります。

SELECT * FROM Test WHERE setstate LIKE '%AZ%';

このメソッドはインデックスを使用できますが、あいまい一致のために多少遅くなります。

SELECT * FROM Test WHERE FIND_IN_SET('AZ',setstate);

この方法はあいまい一致よりも高速ですが、その性質上、ほとんどの実際の使用では一時テーブルを使用する必要があります。

于 2012-12-22T05:48:17.623 に答える