用于选择多个美国州或“全部”的架构设计

时间:2012-12-22 05:42:48

标签: mysql schema

作为一个简单的例子,假设我正在销售小部件。我在全国范围内销售它们(在美国和加拿大)但有一些只能在某些地区(一个或多个美国或加拿大省份)出售。

我想要一种存储此信息的好方法,以及快速查询给定用户可用的小部件的方法。 “美国,50个州和D.C.”是最常见的值,所以我宁愿不插入51行。

MySQL不支持位图索引,因此排除了。

以下是一些组合:

  • U.S。 50个州和D.C。
  • U.S。 50个州,加拿大,但不是魁北克省。
  • U.S。 48个连续的州和D.C。
  • 美国,D.C。,但不是科罗拉多
  • 美国,D.C。和领地(波多黎各等)。

我的用户将为我们的州/省和国家/地区提供一个值。

您能否建议一个提供良好存储和快速匹配的架构?

谢谢!

2 个答案:

答案 0 :(得分: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 Fiddle DEMO

答案 1 :(得分:0)

这是一个MySQL SET类型,假设您可以将数据集保持为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可能比在查找表上添加大量额外的连接操作更便宜,这些操作可以轻松地在其上打开大量的记录。 / p>

下面是3个(功能上)等效拉力。请注意,位掩码是提取此数据的最快方法:

SELECT * FROM Test WHERE setstate & 1000;

对于测试#1,我们使用1000作为位掩码,因为这对应于列表(AZ)中的项目#4。到目前为止,这是最快的方法......并且存储这些数据的方法很少,这将为您提供更快的结果潜力。

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

此方法可以使用索引,但由于模糊匹配会稍微缓慢。

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

这种方法比模糊匹配更快,但其性质几乎需要在大多数实际使用中使用临时表。