可能重复:
Is storing a delimited list in a database column really that bad?
我一直在研究几个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通常都在进行全表扫描。如果没有性能优势,在哪些实例中使用逗号分隔的整数列表是有益的?在创建FIND_IN_SET时,似乎mysql设计师有一些想法。
答案 0 :(得分:6)
你没错,FIND_IN_SET()无法使用索引,因此会导致全表扫描。从技术上讲,该函数对于关系数据库来说是一种虚假的操作,但毫无疑问它有很多需求,所以MySQL实现了它。
以逗号分隔列表存储数据是非规范化的一个示例。任何偏离规范化设计都可以为一种类型的查询提供性能提升,但通常以牺牲针对相同数据的所有其他类型的查询为代价。
例如,如果您将玩家及其团队存储为以逗号分隔的列表,则可以轻松获取给定玩家的团队列表,而无需进行联接。这是性能提升。但是获取给定玩家团队的详细信息要困难得多。同样地搜索特定团队中的所有玩家。
仅当该列表被视为离散的“黑匣子”数据时,才使用逗号分隔列表。即您的应用程序需要将该列表作为整个项目获取,但从不是列表的子集,您永远不需要编写SQL来使用该列表中的元素进行搜索,加入,排序,小计等等。
另请参阅我对Is storing a delimited list in a database column really that bad?
的回答答案 1 :(得分:3)
表扫描在任何时候都不能被视为一种好处。
此外,就我记得从学校来说,它打破了普通形式(http://en.wikipedia.org/wiki/Database_normalization)。
我认为将所有主键/外键列编入索引以获得性能优势是一种很好的做法。
在这种情况下,我唯一的想法就是礼貌地询问建筑师对特定项目的解决方案背后的想法,并解释他/她背后的性能灾难:)