关于数据库的设计问题。过多的字段会影响数据库性能??

superj 2010-06-09 08:27:04
自己正开发一个CMS系统,全靠自己的个人爱好。无偿式的。
编写了一部分了。由于我想考虑周全点,所以数据库表的字段都很长。大约30个左右。


现在公司为我们免费培训。来了一个北大青鸟老师。看了我设计的东西。说我这个数据库设计太不科学了。数据库字段过多。影响效率。而且无法扩展。每次改动都要改动很多。

他说应该把没有强依赖的属性放到另一张表里。这个表里只有两个列属性名和属性值。意思就是列变行。这样易于扩展。
我实在想不通。如果有20个属性。一万条文章,那么到那个表里就产生二十万。这样不是效率更低吗??而且还要联表读取。

他说这样可以建索引,速度快。

放上我的一个文章表的实例和说明。请各位高手来指点一下。
articleId; 主键 文章ID
titleColor; 标题颜色
title; 标题
classId; 分类ID
parentPath; 分类的父路径(因为是树形目录。为了一次读出一个分类下的所有子分类下的文章,所以加了这个字段。
isImage; 是否为图片文章(
imagesUrl; 图片文章链接
fullContent; 文章内容
source; 文章来源。
sourceUrl; 来源URL
linkUrl; 外部链接(意思为这个文章仅仅是一个链接)
keyword; 关键字
viewCount; 浏览数
commentCount; 评论数
importer; 录入者
importerId; 录入都ID (这两个字段我当时不知道怎么思考的。其实录入者就是管理员,但录入者也可能是用户提交的文章,这时可以为空)
author; 作者
authorId; 作者ID (这个字段同上。作者可能是提交文章的用户,也可能是原作者的文章,比如转的文章)
createTime; 添加时间
paginationType; 分页类形(自动手动不分页)
pageWordCount; 每页字数
isDelete; 是否删除,删除会进垃圾箱
isPass; 是否通过。意思就是在审核中。
isComment; 是否允许评论
isCheckComment; 评论是否要审核。
isTop; 是否置顶。
isCommend; 是否推荐。
readme; 文章接要
specialId; 文章所属专题ID
...全文
1440 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
feilniu 2010-06-10
  • 打赏
  • 举报
回复
EAV设计的问题:
1. 不同的属性可能有不同的数据类型,放在一个所谓属性值的列里,则不可避免要大量的数据转换,性能、准确性和精度都很难保证。
2. 考虑一下要给实体加约束(包括外键约束和check约束),你要怎么实现。
3. 如果不同的实体可以有不同的属性,你的逻辑要怎么实现?如果同一类实体含有相同的属性,这跟关系型设计有什么区别?
4. 真的要实现所谓敏捷开发数据建模,可以考虑使用XML或NoSQL等更适合自由格式数据的技术。关系数据库的优势在于数据的完整性和事务的ACID性。在RDBMS中使用EAV模型管理自由格式数据,就好比拿了一把冲锋枪去跟敌人拼刺刀,以己之短,攻人所长。


字段长会不会影响效率?
在SQLServer中,只要你的字段总长不至于使得一行记录大小超过8096字节,就不会出现问题。
单行记录过大会影响一定的性能(因为同样的记录数将需要更多的页,增加读取次数),可以根据字段的逻辑关系和使用频率对表进行拆分,用主键关联。
例如:
表(主键,字段1,字段2,……,不常用字段3,不常用字段4,……)
可以拆分为:
表1(主键,字段1,字段2,……)
表2(主键,不常用字段3,不常用字段4,……)
superj 2010-06-10
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 dawugui 的回复:]

他说这样可以建索引,速度快。

我也这么说.
[/Quote]

晕。你级别最高,那你到底说下。应不应该这样设计。还有字段长会不会影响效率。
feilniu 2010-06-09
  • 打赏
  • 举报
回复
这个表里只有两个列属性名和属性值。

这种EAV模型是出了名的糟糕设计。北大青鸟,果然名不虚传。
dawugui 2010-06-09
  • 打赏
  • 举报
回复
另外如果涉及到归属关系的,可以按照树的思维来设计.以下为2000和2005的两种方案.

/*
标题:SQL SERVER 2000中查询指定节点及其所有子节点的函数(表格形式显示)
作者:爱新觉罗·毓华(十八年风雨,守得冰山雪莲花开)
时间:2008-05-12
地点:广东深圳
*/

create table tb(id varchar(3) , pid varchar(3) , name varchar(10))
insert into tb values('001' , null , '广东省')
insert into tb values('002' , '001' , '广州市')
insert into tb values('003' , '001' , '深圳市')
insert into tb values('004' , '002' , '天河区')
insert into tb values('005' , '003' , '罗湖区')
insert into tb values('006' , '003' , '福田区')
insert into tb values('007' , '003' , '宝安区')
insert into tb values('008' , '007' , '西乡镇')
insert into tb values('009' , '007' , '龙华镇')
insert into tb values('010' , '007' , '松岗镇')
go

--查询指定节点及其所有子节点的函数
create function f_cid(@ID varchar(3)) returns @t_level table(id varchar(3) , level int)
as
begin
declare @level int
set @level = 1
insert into @t_level select @id , @level
while @@ROWCOUNT > 0
begin
set @level = @level + 1
insert into @t_level select a.id , @level
from tb a , @t_Level b
where a.pid = b.id and b.level = @level - 1
end
return
end
go

--调用函数查询001(广东省)及其所有子节点
select a.* from tb a , f_cid('001') b where a.id = b.id order by a.id
/*
id pid name
---- ---- ----------
001 NULL 广东省
002 001 广州市
003 001 深圳市
004 002 天河区
005 003 罗湖区
006 003 福田区
007 003 宝安区
008 007 西乡镇
009 007 龙华镇
010 007 松岗镇

(所影响的行数为 10 行)
*/

--调用函数查询002(广州市)及其所有子节点
select a.* from tb a , f_cid('002') b where a.id = b.id order by a.id
/*
id pid name
---- ---- ----------
002 001 广州市
004 002 天河区

(所影响的行数为 2 行)
*/

--调用函数查询003(深圳市)及其所有子节点
select a.* from tb a , f_cid('003') b where a.id = b.id order by a.id
/*
id pid name
---- ---- ----------
003 001 深圳市
005 003 罗湖区
006 003 福田区
007 003 宝安区
008 007 西乡镇
009 007 龙华镇
010 007 松岗镇

(所影响的行数为 7 行)
*/

drop table tb
drop function f_cid



@@ROWCOUNT:返回受上一语句影响的行数。
返回类型:integer。
注释:任何不返回行的语句将这一变量设置为 0 ,如 IF 语句。
示例:下面的示例执行 UPDATE 语句并用 @@ROWCOUNT 来检测是否有发生更改的行。

UPDATE authors SET au_lname = 'Jones' WHERE au_id = '999-888-7777'
IF @@ROWCOUNT = 0
print 'Warning: No rows were updated'

结果:

(所影响的行数为 0 行)
Warning: No rows were updated



/*
标题:SQL SERVER 2005中查询指定节点及其所有子节点的方法(表格形式显示)
作者:爱新觉罗·毓华(十八年风雨,守得冰山雪莲花开)
时间:2010-02-02
地点:新疆乌鲁木齐
*/

create table tb(id varchar(3) , pid varchar(3) , name nvarchar(10))
insert into tb values('001' , null , N'广东省')
insert into tb values('002' , '001' , N'广州市')
insert into tb values('003' , '001' , N'深圳市')
insert into tb values('004' , '002' , N'天河区')
insert into tb values('005' , '003' , N'罗湖区')
insert into tb values('006' , '003' , N'福田区')
insert into tb values('007' , '003' , N'宝安区')
insert into tb values('008' , '007' , N'西乡镇')
insert into tb values('009' , '007' , N'龙华镇')
insert into tb values('010' , '007' , N'松岗镇')
go

DECLARE @ID VARCHAR(3)

--查询ID = '001'的所有子节点
SET @ID = '001'
;WITH T AS
(
SELECT ID , PID , NAME
FROM TB
WHERE ID = @ID
UNION ALL
SELECT A.ID , A.PID , A.NAME
FROM TB AS A JOIN T AS B ON A.PID = B.ID
)
SELECT * FROM T ORDER BY ID
/*
ID PID NAME
---- ---- ----------
001 NULL 广东省
002 001 广州市
003 001 深圳市
004 002 天河区
005 003 罗湖区
006 003 福田区
007 003 宝安区
008 007 西乡镇
009 007 龙华镇
010 007 松岗镇

(10 行受影响)
*/

--查询ID = '002'的所有子节点
SET @ID = '002'
;WITH T AS
(
SELECT ID , PID , NAME
FROM TB
WHERE ID = @ID
UNION ALL
SELECT A.ID , A.PID , A.NAME
FROM TB AS A JOIN T AS B ON A.PID = B.ID
)
SELECT * FROM T ORDER BY ID
/*
ID PID NAME
---- ---- ----------
002 001 广州市
004 002 天河区

(2 行受影响)
*/

--查询ID = '003'的所有子节点
SET @ID = '003'
;WITH T AS
(
SELECT ID , PID , NAME
FROM TB
WHERE ID = @ID
UNION ALL
SELECT A.ID , A.PID , A.NAME
FROM TB AS A JOIN T AS B ON A.PID = B.ID
)
SELECT * FROM T ORDER BY ID
/*
ID PID NAME
---- ---- ----------
003 001 深圳市
005 003 罗湖区
006 003 福田区
007 003 宝安区
008 007 西乡镇
009 007 龙华镇
010 007 松岗镇

(7 行受影响)
*/

drop table tb

--注:除ID值不一样外,三个SQL语句是一样的。

dawugui 2010-06-09
  • 打赏
  • 举报
回复
他说这样可以建索引,速度快。

我也这么说.
永生天地 2010-06-09
  • 打赏
  • 举报
回复
整体是一个对象,不分为好,
Q315054403 2010-06-09
  • 打赏
  • 举报
回复
不把别人评论为傻蛋,何以描述自己是砖家高手呢

分类可以设计为BOM架构,更灵活,效率更好

27,579

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 应用实例
社区管理员
  • 应用实例社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧