如果应用服务器和数据服务器是分开的,那么你更要考虑之间的通讯成本了。还有你说要节省空间,整数当然比字符串节省空间吧?比如保存 2147483647,整数还是 4 个字节, 如果你用 varchar 需要 10 个字节,用 nvarchar 需要 20 个字节。如果你要查找哪些会员订阅了功能 23,用数字的的话,是直接 where f = 23 的,直接就可以比较, 用字符串是 where f like '%,23,%' 别以为写出来都一样简单,处理可不一样,like '%,23,%' 是要在字符串中搜索子字符串“,23,”的,所有操作肯定比 直接的数字比较慢吧?
方案三: 会员表:会员ID,....... 功能表:功能ID,....... 会员功能表: 会员ID,功能ID 1、增加会员: 只更新会员表,不影响其它表。 2、变更会员功能: 取消功能:delete 会员功能表 where 会员ID=@会员ID and 功能ID=@功能ID 新增功能:insert 会员功能表 select @会员ID,@功能ID 3、删除会议: delete 会员功能表 where 会员ID=@会员ID 其它删除会员的操作。 4、增加功能: 只更新功能表,不影响其它表。 5、变更功能对应的用户: 取消用户:delete 会员功能表 where 会员ID=@会员ID and 功能ID=@功能ID 新增用户:insert 会员功能表 select @会员ID,@功能ID 6、删除功能: delete 会员功能表 where 功能ID=@功能ID 其它删除功能的操作。上述6种操作都很方便,逻辑清晰,性能最佳。 如果进行批量操作,操作的对象放在临时表中,通过两表联合完成。
功能表: Function id(int),title 1,新闻订阅 2,XX 4,YY 8,ZZ会员表: User id,FunctionId(int),Name 1,7,xxx --说明有功能:新闻订阅,XX,YY 2,9,yyy --说明有功能:新闻订阅,ZZ 3,6,zzz --说明有功能:XX,YY--功能ID列为int类型,可以有31种功能,如果不够用bigint 可以有63种功能.--SQL查询 如:包含"新闻订阅"功能的用户 select * from user where functionid & 1 = 1去除所有用户的"ZZ"功能. update user set FunctionId=FunctionId-8 where functionid & 8 = 8
几天都没有人能回答,SQL一日不如一日了.
去除所有用户的"ZZ"功能. update user set FunctionId=FunctionId-8 where functionid & 8 = 8 ------------------------------------------------- 就这条语句,如果用户过百万的话,你就等着吧,即便FUNCTIONID建了索引也没用。
我细的看了下 你的那个 int 字段是 功能里面的ID 加起来的数值从来没见过这么设置的 学习了 研究下
你的功能表里面的ID 是 2的 N 次方? N 从 0开始 吧 ?--SQL查询 如:包含"新闻订阅"功能的用户 select * from user where functionid & 1 = 1 去除所有用户的"ZZ"功能. update user set FunctionId=FunctionId-8 where functionid & 8 = 8 你写的这个 &1=1 我不是很理解
1.这种所谓的动态功能,动的频率应该不高(对于每个会员而言),
2.数据处理复杂、字段会非常大,可能通过再优化解决,比方说将功能表中一个功能对应一条记录,改为一个功能对应N条记录(根据会员ID所在区间分开存放)方案三虽然易于理解,方便实现,但效率应该不高,相比之下二更佳,个人观点,呵呵。
1 0 0 1 1
2 1 0 1 0这样遍历的话绝对快,就算对500w记录,也可以在几秒之内遍历完成一个数据页8k,一条记录不会超过20字节,所以每页可以容纳400条记录400×10000页面=400万记录 磁盘的容量大概是8K×10000=80M ,80M对服务器来说小意思拉,几秒的事。
建个表
功能ID 会员ID
1 1
1 2
2 1
2 2
最传统的做法,实现比较简单,也比较好维护。
如果数据量很大且功能几乎没有变化可考虑 艺术老鼠 的方法.
如果你用 varchar 需要 10 个字节,用 nvarchar 需要 20 个字节。如果你要查找哪些会员订阅了功能 23,用数字的的话,是直接 where f = 23 的,直接就可以比较,
用字符串是 where f like '%,23,%' 别以为写出来都一样简单,处理可不一样,like '%,23,%'
是要在字符串中搜索子字符串“,23,”的,所有操作肯定比 直接的数字比较慢吧?
会员表:会员ID,.......
功能表:功能ID,.......
会员功能表: 会员ID,功能ID
1、增加会员:
只更新会员表,不影响其它表。
2、变更会员功能:
取消功能:delete 会员功能表 where 会员ID=@会员ID and 功能ID=@功能ID
新增功能:insert 会员功能表 select @会员ID,@功能ID
3、删除会议:
delete 会员功能表 where 会员ID=@会员ID
其它删除会员的操作。
4、增加功能:
只更新功能表,不影响其它表。
5、变更功能对应的用户:
取消用户:delete 会员功能表 where 会员ID=@会员ID and 功能ID=@功能ID
新增用户:insert 会员功能表 select @会员ID,@功能ID
6、删除功能:
delete 会员功能表 where 功能ID=@功能ID
其它删除功能的操作。上述6种操作都很方便,逻辑清晰,性能最佳。
如果进行批量操作,操作的对象放在临时表中,通过两表联合完成。
id(int),title
1,新闻订阅
2,XX
4,YY
8,ZZ会员表: User
id,FunctionId(int),Name
1,7,xxx --说明有功能:新闻订阅,XX,YY
2,9,yyy --说明有功能:新闻订阅,ZZ
3,6,zzz --说明有功能:XX,YY--功能ID列为int类型,可以有31种功能,如果不够用bigint 可以有63种功能.--SQL查询
如:包含"新闻订阅"功能的用户
select * from user where functionid & 1 = 1去除所有用户的"ZZ"功能.
update user set FunctionId=FunctionId-8 where functionid & 8 = 8
update user set FunctionId=FunctionId-8 where functionid & 8 = 8
-------------------------------------------------
就这条语句,如果用户过百万的话,你就等着吧,即便FUNCTIONID建了索引也没用。
你的方法不光浪费大量空间,而且逻辑相对复杂,效率也不见得能占上风.你去测试一下,一百万还不够多,我等着看你的测试报告.
id,FunctionId(int),Name
1,7,xxx --说明有功能:新闻订阅,XX,YY
2,9,yyy --说明有功能:新闻订阅,ZZ
3,6,zzz --说明有功能:XX,YY --功能ID列为int类型,可以有31种功能,如果不够用bigint 可以有63种功能. 不太明白 冬眠的鼹鼠 V2.0 的这个表我一个会员拥有的功能是多个的 怎么用 int 类型?我技术不是很好。。
id,FunctionId(int),Name
1,7,xxx --说明有功能:新闻订阅,XX,YY 7=1+2+4 对应功能表中相应ID=1,2,4的功能2,9,yyy --说明有功能:新闻订阅,ZZ 9=1+8
3,6,zzz --说明有功能:XX,YY 6=2+4
如:包含"新闻订阅"功能的用户
select * from user where functionid & 1 = 1 去除所有用户的"ZZ"功能.
update user set FunctionId=FunctionId-8 where functionid & 8 = 8
你写的这个 &1=1 我不是很理解
create table dd_Function (
id int not null primary key
,name varchar(32)
)
insert into dd_Function values (1,'新闻')
insert into dd_Function values (2,'体育')
insert into dd_Function values (3,'生活')
..
create table rl_userFunctions (
userId int primary key -- FK to bo_User
,functions int
)
..
insert into rl_userFunctions values (1,7)
insert into rl_userFunctions values (9,5)
..userID 拥有的功能列表为 functions -- 一个int,将其转换为二进制数值,第bit位的值是是否有第bit功能的标志。
按上面示例的字典,user9有“新闻”,“生活”的功能,则其functions值为:2^(1-1)+2^(3-1) = 5;
若某user1的functions为7,表示其有“新闻”(bit1=1),“体育”(bit2=1),“生活”(bit3=1)功能;该方案与你的‘方案2’相似,但功能数量受限。有些系统将functions扩展为char(?)型的以允许存放更多的条目。
第3种方案很标准,也很高效。没有必要为了存储空间计较
而且如果是INT类型,那也占用不了多少。
发表于:2008-02-20 15:54:0846楼 得分:0
我就不明白这种问题有什么可讨论的,方案一和二连第一范式都不满足,反正我是不会让某个字段是逗号分隔的的字符串的,每一列应该是原子的。
对于你说这些呢,只是范式规则而已,每一列应该是原子这也仅仅是在理论上。许多情况是需要做冗余的,可不能死守范式,呵呵。