假设我有一个包含三列的大表:“user_name”,“user_property”,“value_of_property”。 Lat也假设我有很多用户(比如10万)和很多属性(比方说10 000)。然后表格将是巨大的(10亿行)。
当我从表中提取信息时,我总是需要有关特定用户的信息。所以,我使用,例如where user_name='Albert Gates'
。因此,每次mysql服务器需要分析10亿行时,找到包含“Albert Gates”作为user_name的那些行。
将大表分成许多与固定用户相对应的小表是不明智的?
答案 0 :(得分:5)
不,我认为这不是一个好主意。更好的方法是user_name
列上的add an index - 或者(user_name, user_property)
上的另一个索引,用于查找单个属性。然后数据库不需要扫描所有行 - 它只需要在索引中找到存储在B-Tree中的相应条目,这样可以在很短的时间内轻松找到记录。 / p>
如果您的应用程序即使在正确编制索引后仍然很慢,那么partition最大的表格有时是个好主意。
您可以考虑的另一件事是规范化您的数据库,以便user_name存储在一个单独的表中,并在其位置使用整数foriegn键。这可以降低存储要求并可以提高性能。这同样适用于user_property
。
答案 1 :(得分:3)
您应该规范化您的设计,如下所示:
drop table if exists users;
create table users
(
user_id int unsigned not null auto_increment primary key,
username varbinary(32) unique not null
)
engine=innodb;
drop table if exists properties;
create table properties
(
property_id smallint unsigned not null auto_increment primary key,
name varchar(255) unique not null
)
engine=innodb;
drop table if exists user_property_values;
create table user_property_values
(
user_id int unsigned not null,
property_id smallint unsigned not null,
value varchar(255) not null,
primary key (user_id, property_id),
key (property_id)
)
engine=innodb;
insert into users (username) values ('f00'),('bar'),('alpha'),('beta');
insert into properties (name) values ('age'),('gender');
insert into user_property_values values
(1,1,'30'),(1,2,'Male'),
(2,1,'24'),(2,2,'Female'),
(3,1,'18'),
(4,1,'26'),(4,2,'Male');
从性能角度来看,innodb聚集索引在这个类似的例子(COLD run)中有奇效:
select count(*) from product
count(*)
========
1,000,000 (1M)
select count(*) from category
count(*)
========
250,000 (500K)
select count(*) from product_category
count(*)
========
125,431,192 (125M)
select
c.*,
p.*
from
product_category pc
inner join category c on pc.cat_id = c.cat_id
inner join product p on pc.prod_id = p.prod_id
where
pc.cat_id = 1001;
0:00:00.030: Query OK (0.03 secs)
答案 2 :(得分:2)
正确索引数据库将是提高性能的第一种方法。我曾经有一个查询花了半个小时(在一个大型数据集上,但也是如此)。然后我们发现表没有索引。索引后,查询花费的时间不到10秒。
答案 3 :(得分:1)
为什么需要具有此表结构。我的基本问题是,每次要使用它时,您都必须将数据转换为属性值。这在我看来是不好的 - 因为无论如何,将数字存储为文本是疯狂的。例如,你将如何获得必填字段?或者需要基于其他字段的约束的字段?例如开始和结束日期?
为什么不简单地将属性作为字段而不是多对多关系?
有1张平台。当您的业务规则开始显示应该对属性进行分组时,您可以考虑将它们移出到其他表中,并与users表有几个1:0-1的关系。但这不是规范化,并且由于额外的连接会稍微降低性能(但是表名的自我记录性质将极大地帮助任何开发人员)
我经常看到databqase性能被完全阉割的一种方法是使用泛型
Id,属性类型,属性名称,属性值表。
这是非常懒惰但非常灵活但完全杀死了性能。事实上,在性能不好的新工作中,我实际上会问他们是否有一个具有这种结构的表 - 它总是成为数据库的中心点而且速度很慢。关系数据库设计的关键在于提前确定关系。这只是一种旨在以巨大的应用速度成本加速开发的技术。它还非常依赖应用程序层中的业务逻辑来表现 - 这根本不是防御性的。最终你会发现你想在关键关系中使用属性,导致连接上的所有类型的转换,这进一步降低了性能。
如果数据与实体的关系为1:1,那么它应该是同一个表中的一个字段。如果你的表格超过30个字段,那么考虑将它们移动到另一个表中,但不要将其称为规范化,因为它不是。这是一种技术,可以帮助开发人员以牺牲性能为代价将字段组合在一起,以帮助理解。
我不知道mysql是否有等价但sqlserver 2008有稀疏列 - 空值不占用空间。 SParse column datatypes
我不是说EAV方法总是错误的,但我认为使用关系数据库来实现这种方法可能不是最佳选择。