近日在设计《威博文件管理系统》的文件标签系统中的一点体会。
近来根据用户反馈和原定的开发计划,为《威博文件管理系统》设计一个“文件标签”模块,实现的功能类似于很多大型网站的标签功能,能够实现智能标签功能。
开始的数据库表结构,使用一个单一的“文件标签”表,文件标签表,结构如下:
主键:char(36)
标签名称:varchar(50)
标签排序:int
主观权重:bit
主观推荐:bit
时间戳:bigint
版本号:int
引用计数:int
点击计数:int
@Entity
@Table(name = "文件标签")
public class FileTagModel implements Serializable {
/**
* 使用java的UUID唯一号,36长度的字符串
*/
@Id
@Column(name = "主键")
private String id;
/**
* 标签名称
*/
@Column(name = "标签名称")
private String tagName;
/**
* 标签排序
*/
@Column(name = "标签排序")
private int px;
/**
* 主观权重
*/
@Column(name = "主观权重")
private boolean tagWeight;
/**
* 主观推荐
*/
@Column(name = "主观推荐")
private boolean tagSuggest;
/**
* 实体创建时的时间戳
*/
@Column(name = "时间戳")
private long timestamp;
/**
* 实体对象的版本号
*/
@Column(name = "版本号")
@Version
private int version;
/**
* 点击计数
*/
@Column(name = "点击计数")
private int clickCount;
/**
* 引用计数
*/
@Column(name = "引用计数")
private int quoteCount;
}
经过一段时间的测试后发现,“文件标签”表中,各个字段的的变化速度有很大的不同,其中引用计数、点击计数、变化很频繁,而其它字段的内容相对变化
就比较稳定,一旦生成,相对比较稳定,这样在并发程度高时,常常导致数据更新冲突,虽然可以通过@version注解可以保证数据的乐观锁定发生作用,数
据的一致性不被破坏。但是由于把变化频度差异很大的字段放在同一张表上,导致冲突发生的概率增大,降低了系统的效能。
于是想到了对该表的横向切割,以便获得更好的并发性能。
切割后,分为三个表,《文件标签》作为主表,《文件标签引用计数》《文件标签点击计数》作为从表,三个表共用主键,三表结构如下:
《文件标签》表结构
主键:char(36)
标签名称:varchar(50)
标签排序:int
主观权重:bit
主观推荐:bit
时间戳:bigint
版本号:int
《文件标签引用计数》表结构
主键:char(36)
引用计数:int
时间戳:bigint
版本号:int
《文件标签点击计数》表结构
主键:char(36)
点击计数:int
时间戳:bigint
版本号:int
《文件标签》表实体Bean
package cn.sh.webfile.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import javax.persistence.Version;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
/**
* 开始于 2010-06-09
* 文件标签符号表的模型
* [2010-06-18修]新增加一个字段
* [2010-06-21修]根据应用程序的使用反馈,把引用计数、点击计数字段,放入两个不同的表
* 以实现更好的多工状态下的并发操作,减少状态冲突。分拆理由,表《文件标签》主表、《文件标签引用计数》、
* 《文件标签点击计数》作为从表,主表变化慢,从表变化快。
* 最后修改于 2010-06-21
* @author 万继斌
* @version 1.3
*/
@Entity
@Table(name = "文件标签")
public class FileTagModel implements Serializable {
/**
* 使用java的UUID唯一号,36长度的字符串
*/
@Id
@Column(name = "主键")
private String id;
/**
* 标签名称
*/
@Column(name = "标签名称")
private String tagName;
/**
* 标签排序
*/
@Column(name = "标签排序")
private int px;
/**
* 主观权重
*/
@Column(name = "主观权重")
private boolean tagWeight;
/**
* 主观推荐
*/
@Column(name = "主观推荐")
private boolean tagSuggest;
/**
* 实体创建时的时间戳
*/
@Column(name = "时间戳")
private long timestamp;
/**
* 实体对象的版本号
*/
@Column(name = "版本号")
@Version
private int version;
/**
* 点击计数
*/
@OneToOne
@PrimaryKeyJoinColumn
private FileTagClickCountModel clickCount;
/**
* 引用计数
*/
@OneToOne
@PrimaryKeyJoinColumn
private FileTagQuoteCountModel quoteCount;
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
/**
* @return the id
*/
public String getId() {
return id.trim();
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id.trim();
}
/**
* @return the timestamp
*/
public long getTimestamp() {
return timestamp;
}
/**
* @param timestamp the timestamp to set
*/
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
/**
* @return the version
*/
public int getVersion() {
return version;
}
/**
* @param version the version to set
*/
public void setVersion(int version) {
this.version = version;
}
/**
* @return the tagName
*/
public String getTagName() {
return tagName.trim();
}
/**
* @param tagName the tagName to set
*/
public void setTagName(String tagName) {
this.tagName = tagName.trim();
}
/**
* @return the tagWeight
*/
public boolean getTagWeight() {
return tagWeight;
}
/**
* @param tagWeight the tagWeight to set
*/
public void setTagWeight(boolean tagWeight) {
this.tagWeight = tagWeight;
}
/**
* @return the px
*/
public int getPx() {
return px;
}
/**
* @param px the px to set
*/
public void setPx(int px) {
this.px = px;
}
/**
* @return the tagSuggest
*/
public boolean isTagSuggest() {
return tagSuggest;
}
/**
* @param tagSuggest the tagSuggest to set
*/
public void setTagSuggest(boolean tagSuggest) {
this.tagSuggest = tagSuggest;
}
/**
* @return the clickCount
*/
public FileTagClickCountModel getClickCount() {
return clickCount;
}
/**
* @param clickCount the clickCount to set
*/
public void setClickCount(FileTagClickCountModel clickCount) {
this.clickCount = clickCount;
}
/**
* @return the quoteCount
*/
public FileTagQuoteCountModel getQuoteCount() {
return quoteCount;
}
/**
* @param quoteCount the quoteCount to set
*/
public void setQuoteCount(FileTagQuoteCountModel quoteCount) {
this.quoteCount = quoteCount;
}
}
《文件标签引用计数》表实体Bean
package cn.sh.webfile.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Version;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
/**
* 开始于 2010-06-21
* 文件标签引用计数表的模型
* 《文件标签引用计数》作为从表,主表变化慢,从表变化快。
* 最后修改于 2010-06-21
* @author 万继斌
* @version 1.0
*/
@Entity
@Table(name = "文件标签引用计数")
public class FileTagQuoteCountModel implements Serializable {
/**
* 使用java的UUID唯一号,36长度的字符串
*/
@Id
@Column(name = "主键")
private String id;
/**
* 引用计数
*/
@Column(name = "引用计数")
private int count;
/**
* 实体创建时的时间戳
*/
@Column(name = "时间戳")
private long timestamp;
/**
* 实体对象的版本号
*/
@Column(name = "版本号")
@Version
private int version;
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
/**
* @return the id
*/
public String getId() {
return id.trim();
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id.trim();
}
/**
* @return the timestamp
*/
public long getTimestamp() {
return timestamp;
}
/**
* @param timestamp the timestamp to set
*/
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
/**
* @return the version
*/
public int getVersion() {
return version;
}
/**
* @param version the version to set
*/
public void setVersion(int version) {
this.version = version;
}
/**
* @return the count
*/
public int getCount() {
return count;
}
/**
* @param count the count to set
*/
public void setCount(int count) {
this.count = count;
}
}
《文件标签点击计数》表实体Bean
package cn.sh.webfile.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Version;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
/**
* 开始于 2010-06-21
* 文件标签点击计数表的模型
* 《文件标签点击计数》变化较快的表。
* 最后修改于 2010-06-21
* @author 万继斌
* @version 1.0
*/
@Entity
@Table(name = "文件标签点击计数")
public class FileTagClickCountModel implements Serializable {
/**
* 使用java的UUID唯一号,36长度的字符串
*/
@Id
@Column(name = "主键")
private String id;
/**
* 点击计数
*/
@Column(name = "点击计数")
private int count;
/**
* 实体创建时的时间戳
*/
@Column(name = "时间戳")
private long timestamp;
/**
* 实体对象的版本号
*/
@Column(name = "版本号")
@Version
private int version;
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
/**
* @return the id
*/
public String getId() {
return id.trim();
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id.trim();
}
/**
* @return the timestamp
*/
public long getTimestamp() {
return timestamp;
}
/**
* @param timestamp the timestamp to set
*/
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
/**
* @return the version
*/
public int getVersion() {
return version;
}
/**
* @param version the version to set
*/
public void setVersion(int version) {
this.version = version;
}
/**
* @return the count
*/
public int getCount() {
return count;
}
/**
* @param count the count to set
*/
public void setCount(int count) {
this.count = count;
}
}
经过实地测试,并发效能大大提高,而通过对主表的分割,而导致的连接操作带来的速度损失相对较小,某些方面还可以增大综合读写速度。
体会总结如下:
当我们在设计时,发现同一张表内,字段的变化频度差异过大时,为了获得更好的并发操作性能,降低潜在冲突,这时可以对表,进行横向分割,按照字段的
不同的变化频度,合理地置于不同的主从表内,以此来提高性能。特别是在Web应用程序中,使用版本号来进行乐观锁定时,对性能的提高更加有好处,可以大大
降低冲突发生的概率。
分享到:
相关推荐
, 全书主要内容从三个维度展开:首先是内部扩展的维度,深入探讨了高效B树索引、高效表设计、查询优化器等数据库架构设计与优化的核心技术,以及高并发Oracle数据库系统架构与设计的方法论和常见的高并发案例;...
高并发Oracle数据库系统的架构与设计主要内容从三个维度展开:首先是内部扩展的维度,深入探讨了高效B树索引、高效表设计、查询优化器等数据库架构设计与优化的核心技术,以及高并发Oracle数据库系统架构与设计的...
通过T-Sql语句横向显示数据库表中的列数据,非常实用,欢迎下载交流。
1、在日常开发中,业务提供的数据往往是横向数据,不符合开发设计的数据库表,若想转为纵表,手动操作效率太低,为此写了本方法。 2、适用于各类业务场景下的横表转纵表需求,只需要按照对应的表结构修改存储过程...
hive数据库表设计,为适应业务需要,可建横向宽表和竖向宽表
在模型的设计上,我们通常采用第三范式来进行数据库对象的模型设计,但是有时为了性能考虑,我们通常会做一些退化,比如设计一些冗余字段或者多表合并来加快系统的查询性能。例如对于有大量数据的销售流水表,完全...
4.4 分区表设计规范 12 4.2.1 不使用全局索引 12 4.2.2 RANGE分区的规范 12 4.2.3 LIST分区的规范 13 4.2.4 HASH分区的规范 13 4.2.5 RANGE-LIST分区的规范 14 4.2.6 RANGE-HASH分区的规范 14 5 索引的设计规范 15 ...
2、纵向、横向分割表,减少表的尺寸(sp_spaceuse) 3、升级硬件 4、根据查询条件,建立索引,优化索引、优化访问方式,限制结果集的数据量。注意填充因子要适当(最好是使用默认值0)。索引应该尽量小,使用字节数...
行业分类-设备装置-一种降低横向切割阻力的发泡砖切割装置.zip
Mellanox横向扩展数据库解决方案.pdf
前言:今天在开发的时候遇到这样的问题,最外层是ScrollView,里面嵌套了一个横向滑动的日历控件,在滑动日历的时候很卡顿。看到这种问题,自然而然的就会想到scrollview和其他可滑动控件的冲突问题。 解决思路 用户...
金刚石线锯横向超声振动切割SiC单晶表面粗糙度预测_李伦_机械工程专业论文范文模板、范本.pdf
Hbase是Apache的NoSQL分布式可扩展Hadoop数据库,可以很好地横向扩展。Hbase中的数据是面向列的数据库,其中结构化数据存储在键值对中。Hbase用Java编写。Hbase的灵感来自Google Paper-“大表:结构化数据的分布式...
gridview固定表头 横向滚动 纵向固定,即拖动横向滚动条时,表头随着表体移动,纵向拖动滚动条时,表头不动,实践得出来的结果 我用的是VS2010,C#
这个软件可以对图片进行,...如果大家按像素对图片进行横向切割,那么像素宽度填写1,高度随便写;如果按像素对图片进行纵向切割,那么像素高度填写1,像素宽度随便写。没有分割数量限制,没有使用次数限制,任君享用。
gridview固定表头 横向滚动 纵向固定,即拖动横向滚动条时,表头随着表体移动,纵向拖动滚动条时,表头固定不动 实践中所得一个具体实例 VS2010,C#
对于某些数据表来说,字段数很多,打开浏览时,屏幕放不下,需要用横向滚动条来移动查看,为了清楚浏览数据记录,希望在滚动过程中,某些字段不要移动;其二,如果数据表字段很少且比较规范,希望在数据表表格上编辑...
0.前言假如现在存在如下图所示的一张表,这种表在数据库中是很常见,主要包括字段(序号,教师姓名,单位名称,性别,学历)。该表的信息为:TEST_TEACHER
Java基于XGBoost的高效安全横向联邦学习源码(毕业设计).zipJava基于XGBoost的高效安全横向联邦学习源码(毕业设计).zipJava基于XGBoost的高效安全横向联邦学习源码(毕业设计).zipJava基于XGBoost的高效安全横向联邦...