mysql:使用SET还是很多列?

lol*_*ter 6 php mysql database database-design

我正在使用PHP和MySQL.我有以下记录:

  • 具有分层的各种"事件类型"的事件(事件可以有多个类别和子类别,但是有固定数量的此类别和子类别)(带时间戳)

设置表的最佳方法是什么?我是否应该有一堆列(30左右)带有枚举的是或否表示该类别的成员资格?或者我应该使用MySQL SET数据类型? http://dev.mysql.com/tech-resources/articles/mysql-set-datatype.html

基本上我有表现,我希望能够检索给定类别的所有事件的ID.只是寻找一些有关最有效的方法的见解.

joe*_*rdi 10

听起来你主要关注的是性能.

有几个人建议拆分成3个表(类别表加上简单的交叉引用表或更复杂的树层次结构建模方式,如嵌套集或物化路径),这是我在阅读你的问题时首先想到的.

对于索引,像这样的完全标准化方法(添加两个JOIN)仍将具有"非常好"的读取性能.一个问题是对事件的INSERT或UPDATE现在也可能包括一个或多个INSERT/UPDATE/DELETE到交叉引用表,在MyISAM上意味着交叉引用表被锁定,在InnoDB上意味着行被锁定,因此,如果您的数据库忙于大量写入,那么与仅锁定事件行相比,您将遇到更大的争用问题.

就个人而言,我会在优化之前尝试这种完全规范化的方法.但是,我会假设你知道你正在做什么,你的假设是正确的(类别永远不会改变),你有一个使用模式(大量的写入),需要一个较不规范化的扁平结构.这完全没问题,是NoSQL的一部分.

SET与"很多列"

那么,关于你的实际问题"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,因为"按类别选择事件"查询会很慢.