我正在使用PHP和MySQL。我有以下记录:
设置表格的最佳方法是什么?我是否应该有一堆列(30左右)带有枚举的是或否表示该类别的成员资格?或者我应该使用MySQL SET数据类型? http://dev.mysql.com/tech-resources/articles/mysql-set-datatype.html
基本上我有表现,我希望能够检索给定类别的所有事件的ID。只是寻找一些有关最有效的方法的见解。
答案 0 :(得分:9)
听起来你主要关注的是表现。
有几个人建议拆分成3个表(类别表加上简单的交叉引用表或更复杂的树层次结构建模方式,如嵌套集或物化路径),这是我第一次想到的阅读你的问题。
对于索引,像这样的完全规范化的方法(增加两个JOIN)仍将具有“非常好”的读取性能。一个问题是对事件的INSERT或UPDATE现在也可能包括一个或多个INSERT / UPDATE / DELETE到交叉引用表,在MyISAM上意味着交叉引用表被锁定,在InnoDB上意味着行被锁定,因此,如果您的数据库忙于大量写入,那么与仅仅锁定事件行相比,您将遇到更大的争用问题。
就个人而言,我会在优化之前尝试这种完全规范化的方法。但是,我会假设你知道你正在做什么,你的假设是正确的(类别永远不会改变),你有一个使用模式(大量的写入),需要一个较不规范化的扁平结构。这完全没问题,是NoSQL的一部分。
那么,关于你的实际问题“SET与很多专栏”,我可以说我曾与两家拥有智能工程师的公司合作(其产品是CRM网络应用程序......其中一项实际上是事件管理),他们都使用“大量列”方法来处理这种静态集合数据。
我的建议是考虑您将在此表上进行的所有查询(按频率加权)以及索引的工作方式。
首先,使用“大量列”方法,您将需要在每个列上使用索引,以便您可以执行SELECT FROM events WHERE CategoryX = TRUE
。使用索引,这是一个超快查询。
与SET相比,您必须使用按位AND(&),LIKE或FIND_IN_SET()来执行此查询。这意味着查询不能使用索引,必须对所有行进行线性搜索(您可以使用EXPLAIN来验证这一点)。慢查询!
这是SET一个坏主意的主要原因 - 它的索引仅在您选择精确的类别组时才有用。如果您按事件选择类别,SET会很有效,但不是相反。
较少规范化的“大量列”方法(与完全标准化相比)的主要问题是它不能扩展。如果你有5个类别并且它们永远不会改变,那很好,但是如果你有500个并且正在改变它们,这是一个大问题。在您的方案中,大约30个永远不会更改,主要问题是每列都有一个索引,因此如果您正在进行频繁写入,那么由于必须更新的索引数量,这些查询会变慢。如果选择这种方法,您可能需要检查MySQL慢查询日志,以确保在繁忙的一天中由于争用而没有异常缓慢的查询。
在你的情况下,如果你的是一个典型的阅读重量级网络应用程序,我认为采用“大量列”方法(因为两个CRM产品,出于同样的原因)可能是理智的。该SELECT查询的肯定比SET快。
TL; DR 不要使用SET,因为“按类别选择事件”查询会很慢。
答案 1 :(得分:2)
事件和事件类型/类别之间的关系是多对多关系,如echo says,但是一个简单的外部参照表会留下一个问题:如果要查询任何给定节点的所有后代,则必须进行多次递归查询。在一棵深树上,这将是非常低效的。
因此,当您说“检索给定类别的所有ID”时,如果您执行表示所有后代,那么您希望使用嵌套集模型:
http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
嵌套集模型使写入更新速度稍慢,但使非常容易检索子树:
left >= 2
和right <= 9
。left = right - 1
(right - left - 1)/2
答案 2 :(得分:2)
类别数量固定是好的。如果不是,你就不能使用任何一种方法。
检查您链接的页面上的为什么不应该使用SET 。我认为应该给你一个全面的指南。
我认为最重要的是索引。此外,修改SET
稍微复杂一些。
答案 3 :(得分:1)
您可以尝试使用交叉引用(外部参照)表,在事件及其类型之间创建多对多关系。
create table event_category_event_xref
(
event_id int,
event_category_id int,
foreign key(event_id) references event(id),
foreign key (event_category_id) references event_category(id)
);
事件/类别成员资格由此表中的记录定义。因此,如果您有{event_id = 3, event_category_id = 52}
的记录,则表示事件#3属于#52类。同样,您可以拥有{event_id = 3, event_category_id = 27}
的记录,依此类推。