什么是在MySQL列中存储整数数组的最有效方法?

时间:2010-07-16 03:20:52

标签: php mysql optimization search database

我有两张桌子

答:

plant_ID | name.
1        | tree
2        | shrubbery
20       | notashrubbery

B:

area_ID | name    | plants
1       | forrest | *needhelphere*

现在我希望该区域按特定顺序存储任意数量的植物,并且某些植物可能会出现多次:例如2,20,1,2,2,20,1

什么是存储这一系列植物的最有效方式?
请记住,我需要做到这一点,如果我执行搜索以找到植物2的区域,我不会得到例如1,20,232,12,20(带有前导0的垫?)什么会是对此的查询?

如果它有帮助,我们假设我有一个不超过99999999个不同植物的数据库。是的,这个问题与植物没有任何关系......

奖金问题 是时候离开MySQL吗?是否有更好的数据库来管理它?

6 个答案:

答案 0 :(得分:26)

如果你要通过森林和植物进行搜索,听起来你会受益于全面的多对多关系。抛弃您的plants列,并创建一个全新的areas_plants表(或任何您想要调用它的表)来关联这两个表。

如果区域1有植物1和2,区域2有植物2和3,那么您的areas_plants表将如下所示:

area_id | plant_id | sort_idx
-----------------------------
      1 |        1 |     0
      1 |        2 |     1
      2 |        2 |     0
      2 |        3 |     1

然后,您可以从任意一侧查找关系,并使用简单的JOIN从任一表中获取相关数据。不需要在LIKE条件下弄清楚它是否在列表中,等等,等等。我去过遗留数据库。没有什么好玩的。使用SQL发挥最大潜力。

答案 1 :(得分:7)

这个怎么样:

表:植物

plant_ID | name
1        | tree
2        | shrubbery
20       | notashrubbery

表:区域

area_ID | name
1       | forest

table:area_plant_map

area_ID | plant_ID | sequence
1       | 1        | 0
1       | 2        | 1
1       | 20       | 2

这是标准的标准化方法(使用映射表)。

要找到所有带灌木丛的区域(植物2),请执行以下操作:

SELECT *
FROM areas
INNER JOIN area_plant_map ON areas.area_ID = area_plant_map.area_ID
WHERE plant_ID = 2

答案 2 :(得分:3)

你知道这违反了正常形式吗?

通常,会有一个areaplants表:area_ID,plant_ID,对两个表有唯一约束,对其他两个表有外键。这个“链接”表格为您提供了许多或多对一的关系。

对此的查询通常非常有效,它们使用索引而不需要解析字符串。

答案 3 :(得分:2)

您的关系属性应该是原子的,不是由列表等多个值组成。搜索它们太难了。您需要一个新的关系,将植物映射到area_ID,而area_ID /植物组合是主键。

答案 4 :(得分:2)

使用多对多关系:

CREATE TABLE plant (
    plant_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255)
) ENGINE=INNODB;

CREATE TABLE area (
    area_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255)
) ENGINE=INNODB;

CREATE TABLE plant_area_xref (
    plant_id INT NOT NULL,
    area_id INT NOT NULL,
    sort_idx INT NOT NULL,
    FOREIGN KEY (plant_id) REFERENCES plant(plant_id) ON DELETE CASCADE,
    FOREIGN KEY (area_id) REFERENCES area(area_id) ON DELETE CASCADE,
    PRIMARY KEY  (plant_id, area_id, sort_idx)    
) ENGINE=INNODB;

编辑:

只是回答你的红利问题:

Bonus Question Is it time to step away from MySQL? Is there a better DB to manage this?

这与MySQL无关。这只是一个糟糕的数据库设计问题。对于每个RDBMS(MySQL,Oracle,MSSQL,PostgreSQL等)中的情况,您应该使用交集表和多对多关系。

答案 5 :(得分:2)

提出此问题8年后,这里有2个想法:

1。使用json类型(link)

  

从MySQL 5.7.8开始,MySQL支持RFC 7159定义的本机JSON数据类型,从而可以高效地访问JSON(JavaScript对象表示法)文档中的数据。

2。使用您自己的编纂

area_id转换为字符串字段(varchar或text,您可以选择,考虑性能),然后可以将值表示为-21-30-2-4-20-,然后可以使用%-2-%进行过滤。

如果您以某种方式尝试其中的一种,那么如果您共享您的性能结果(建议的结果为1亿行),我将非常喜欢。

-

请记住,不要使用其中任何一个打破标准化的第一条规则,即every column should hold a single value