-1

可能重复:
在数据库列中存储分隔列表真的那么糟糕吗?

我一直在处理几个 PHP/MySQL 项目,其中所有关系都存储为逗号分隔的字符串。

例如,一个共同的关系就像

(在伪代码中)

table people
id - integer
name - string
age - integer
teams - string (CSV OF integers, ex '1,3,9,21')

table teams
name - String
id - integer

管理关系变得很麻烦。

要为一个人获取所有团队:

$person = 'SELECT * FROM People WHERE id= x';

然后在php中我一直在做类似的事情

$person['teams'] = SELECT * FROM teams WHERE id IN ($person['teams']);

当我写这篇文章时,我意识到我可以将它们组合在一个 mysql 查询中,比如:

SELECT 
  people.id, 
  people.name, 
  people.teams, 
  teams.name 
FROM people 
JOIN teams ON FIND_IN_SET(teams.id, people.teams) WHERE people.id=x

使用这种类型的设置,我发现自己FIND_IN_SET经常使用

最后,我的问题是:创建这样的关系是否有性能优势?

到目前为止,根据我的经验,FIND_IN_SET 通常会进行全表扫描。如果没有性能优势,在哪些情况下使用逗号分隔的整数列表是有益的? 似乎 mysql 设计者在创建 FIND_IN_SET 时有一些想法。

4

2 回答 2

6

没错,FIND_IN_SET() 不能使用索引,因此会导致全表扫描。从技术上讲,该功能是关系数据库的虚假操作,但毫无疑问对它有很多需求,因此 MySQL 实现了它。

将数据存储在逗号分隔的列表中是非规范化的一个示例。任何与规范化设计的偏离都可以提高一种查询的性能,但通常以针对相同数据的所有其他类型的查询为代价。

例如,如果您将球员和他们的球队存储为逗号分隔的列表,则无需加入即可轻松获取给定球员的球队列表。这是一个性能改进。但是获取给定球员球队的详细信息要困难得多。同样搜索给定球队的所有球员。

仅当该列表被视为离散的“黑盒”数据时,才使用逗号分隔的列表。即,您的应用程序需要将该列表作为一个整体来获取,而不是列表的子集,并且您永远不需要编写 SQL 来使用该列表中的元素进行搜索、连接、排序、小计等。

另请参阅我对在数据库列中存储分隔列表真的那么糟糕吗?

于 2013-01-22T20:13:04.570 回答
3

表扫描在任何时候都不能被视为一种好处。

此外,据我在学校的记忆,它打破了常规形式(http://en.wikipedia.org/wiki/Database_normalization )。

我认为将所有主/外键列编入索引以提高性能是一种很好的做法。

在这种情况下,我唯一的想法是礼貌地询问特定项目的架构师他的解决方案背后的想法,并解释他/她背后的性能灾难:)

于 2013-01-22T20:06:48.653 回答