【问题标题】:PHP/MySQL: Multiple comma separated values per table field vs... WHAT?PHP/MySQL:每个表字段有多个逗号分隔值与...什么?
【发布时间】:2022-11-19 00:34:05
【问题描述】:

这是一个古老且反复出现的问题,但请原谅我自己没有找到正确的答案,因为每个人的情况或多或少都是独一无二的。除此之外,我需要少一点理论,多一点实践。

谈正事。我知道在单个表字段中存储多个逗号分隔值是众所周知的糟糕设计,因为它会影响性能并破坏关系。尽管如此,直到今天仍有很多人求助于它,因为他们不知道更好或者只是懒惰。直到现在我终于决定让事情变得更好,我的情况也没有什么不同。除了我不确定如何。

情况是这样的。假设我有一张电影表:

+------------------------------+
| id |       name       | year |
+------------------------------+
|  1 |       Alien      | 1979 |
|  2 |  Breakfast Club  | 1985 |
|  3 |    First Blood   | 1982 |
+------------------------------+

现在我需要以某种方式将流派存储在某个地方。显然,我将需要一个单独的流派表,因为将它插入同一个表是不行的。但是如何构造呢?我只能考虑两种方式:使用外键或者布尔类型字段,各有优缺点。

让我们观察第一个:

+---------------------+
| movie_id | genre_id | 
|----------+----------+
|    1     |    2     |
|    1     |    4     |
|    3     |    1     |
+----------+----------|

所以,这里的问题是每个流派惩罚的一行。意思是,如果我需要存储不止一种类型,我将不得不像这样运行多个插入查询:

foreach($genres as $genre_id)
{
    $db->query("INSERT INTO genres (movie_id, genre_id) VALUES ('$movie_id', '$genre_id');
}

那看起来不漂亮。我的意思是,如果我错了请纠正我,但这不是过多的数据库调用吗?而且,显然,这将与引入的流派数量有关。我还应该怎么做?如果有更好的方法,请告诉。

现在第二种情况:

+----------+-----------+--------+-------+----------
| movie_id | adventure | comedy | drama | horror  ...
+----------+-----------+--------+-------+----------
|    1     |     0     |   1    |   0   |    1    ...
+----------+-----------+--------+-------+----------
|    3     |     1     |   0    |   0   |    0    ...
+----------+-----------+--------+-------+----------

好的,这样更好。或者是吗?当然,这将允许我运行单个插入,除了现在它以相当复杂的查询构建过程作为回报:

$query1 = "INSERT INTO genres (movie_id, ";
$query2 = " VALUES ('$movie_id', ";
foreach($genres as $key => $value)
{
    if($value)
    {
        $query1 .= "$key, ";
        $query2 .= "'$value', ";
    }
}
$query = rtrim($query1, ", ") . ")" . rtrim($query2, ", ") . ")";
$db->query($query);

但我想它有效。不过,我不知道这是否非常实用。

坦率地说,我不喜欢这两种方法,我觉得必须有第三种更优雅的解决方案,但我现在无法想象。

【问题讨论】:

  • “好吧,这样更好。还是这样?”- 它实际上比逗号分隔值更糟糕。字符串至少可以被解析/操作/等等。即使它不是很好。但存储数据作为图式(流派作为列名)不仅难以该数据但需要您修改模式任何时候您想更改该数据。您的第一个想法看起来像标准的多对多关系。认为它“看起来不漂亮”并不是避免它的有效技术理由。
  • 除非一部电影有几十种类型,否则我不会担心每种类型都有多个插入。您不会经常添加电影,以至于这种开销很大。

标签: php mysql normalization


【解决方案1】:

您知道单个 INSERT 语句可以插入多行吗?

INSERT INTO genres (movie_id, genre_id) 
VALUES (?, ?),
       (?, ?),
       (?, ?)...

或者,即使您每次调用只执行一行,您也可以使用准备好的语句并使用不同的值多次执行它。

$stmt = $db->prepare("INSERT INTO genres (movie_id, genre_id) VALUES (?, ?)");
foreach($genres as $genre_id)
{
    $stmt->execute([$movie_id, $genre_id]);
}

我不会推荐您的第二个解决方案,将流派存储为布尔列。您很可能会不时添加新类型,每次这样做都需要运行 ALTER TABLE ADD COLUMN,这是一个问题。然后你需要担心 MySQL 在给定表中最多可以支持多少列,等等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-13
    • 2013-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-06
    相关资源
    最近更新 更多