可能的重复项:
在数据库列中存储分隔列表真的那么糟糕吗?
我一直在研究几个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时想到了一些东西。
你是对的,FIND_IN_SET() 无法使用索引,因此会导致全表扫描。 从技术上讲,该功能对于关系数据库来说是一个虚假的操作,但毫无疑问,对它的需求很大,所以MySQL实现了它。
将数据存储在逗号分隔的列表中是非规范化的一个示例。 任何偏离规范化设计的行为都可以提高一种类型的查询的性能,但通常以牺牲针对相同数据的所有其他类型的查询为代价。
例如,如果将玩家及其球队存储为逗号分隔的列表,则无需执行联接即可轻松获取给定玩家的球队列表。 这是一种性能改进。 但是获取给定球员球队的详细信息要困难得多。 同样,搜索给定团队中的所有球员。
仅当该列表被视为离散的"黑盒"数据片段时,才使用该列表。 即,您的应用程序需要将该列表作为整个项目获取,但绝不是列表的子集,并且您永远不需要编写 SQL 来使用该列表中的元素进行搜索、连接、排序、小计等。
另请参阅我的回答 在数据库列中存储分隔列表真的那么糟糕吗?
在任何时候,表扫描都不能被视为一种好处。
此外,据我从学校记得,它打破了正常形式(http://en.wikipedia.org/wiki/Database_normalization)。
我认为将所有主键/外键列索引以获得性能优势是一种很好的做法。
在这种情况下,我唯一的想法是礼貌地询问特定项目的架构师他的解决方案背后的想法是什么,并向他/她解释这个:)背后的性能灾难