大橙子网站建设,新征程启航
为企业提供网站建设、域名注册、服务器等服务
Oracle中我们经常使用Date字段类型记录日期和时间,有的时候还在这个字段上建立索引。
我们提供的服务有:成都网站设计、成都做网站、微信公众号开发、网站优化、网站认证、安达ssl等。为上1000+企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的安达网站制作公司
然后通过Java程序访问数据库的时候,我们很自然的类似这样使用:select * from table where endDate? and endDate?,然后通过PreparedStatement预编译,再通过setTimestamp传入由java.util.Date转成java.sql.Timestamp的参数(因为java.sql.Date只有日期,java.sql.Time只有时间,所以我们只能用java.sql.Timestamp类型)。我们会认为这样应该走索引区间扫描,效率应该是非常高的。
而事实上,Oracle会把sql解释成如下这样来执行:select * from table where TO_TIMESTAMP(endDate)? and TO_TIMESTAMP(endDate)?; 为什么?因为传入的参数是timestamp类型,Oracle从9.2版本以后支持这种类型,所以Oracle做了这样的转换,结果就是这个SQL执行变成了全表扫描。我们做的试验,加了一个index hint,强制走时间索引字段,结果效率也不高,sql执行变成了全索引扫描,和全表扫描没多大区别。结果效率还是低。
不光直接使用JDBC会是这样,Spring,iBatis在处理传入参数是java.util.Date类型的时候,都会使用setTimestamp设定参数,所以都需要注意。
解决办法(四种解决办法,推荐方案一):
1.sql修改成这样:select * from table where endDateto_date(?,’yyyymmddhh24miss’) and endDateto_date(?,’yyyymmddhh24miss’);然后将传入参数格式化成对应格式的字符串在传入,这样由Oracle将字符串转成Date类型,就很顺利的走索引区间扫描,效率最高。
2.在建立数据库连接的时候增加一个属性oracle.jdbc.V8Compatible=true,代码如下:
Properties prop=new Properties();
prop.setProperty(“user”,”****”);
prop.setProperty(“password”,”****”);
prop.setProperty(“oracle.jdbc.V8Compatible”,”true”);
Connection connection = DriverManager.getConnection(“jdbc:oracle:thin:@127.0.0.1:1521:test”, prop);
连接池也根据各自的配置方式增加这个属性即可。目前看来这个属性参数是处理时间映射关系的,但是还不确定它是否会带来其他的问题,所以要慎重使用。
3.修改数据库列类型为timestamp类型。
4.依据网上资料,Oracle 11g修改了驱动 api,使用方式可能也会有改变。因为无法试验,所以也不确定具体细节。
以每24小时作为一份时间(而非自然日),根据用户的配置有两种工作模式:带状模式中,用户仅定义开始日期时,从开始日期(含)开始,每份时间1个分片地无限增加下去;环状模式中,用户定义了开始日期和结束日期时,以结束日期(含)和开始日期(含)之间的时间份数作为分片总数(分片数量固定),以类似取模的方式路由到这些分片里。
1. DBLE 启动时,读取用户在 rule.xml 配置的 sBeginDate 来确定起始时间
2. 读取用户在 rule.xml 配置的 sPartionDay 来确定每个 MySQL 分片承载多少天内的数据
3. 读取用户在 rule.xml 配置的 dateFormat 来确定分片索引的日期格式
4. 在 DBLE 的运行过程中,用户访问使用这个算法的表时,WHERE 子句中的分片索引值(字符串),会被提取出来尝试转换成 Java 内部的时间类型
5. 然后求分片索引值与起始时间的差,除以 MySQL 分片承载的天数,确定所属分片
1. DBLE 启动时,读取用户在 rule.xml 配置的起始时间 sBeginDate、终止时间 sEndDate 和每个 MySQL 分片承载多少天数据 sPartionDay
2. 根据用户设置,建立起以 sBeginDate 开始,每 sPartionDay 天一个分片,直到 sEndDate 为止的一个环,把分片串联串联起来
3. 读取用户在 rule.xml 配置的 defaultNode
4. 在 DBLE 的运行过程中,用户访问使用这个算法的表时,WHERE 子句中的分片索引值(字符串),会被提取出来尝试转换成 Java 内部的日期类型
5. 然后求分片索引值与起始日期的差:如果分片索引值不早于 sBeginDate(哪怕晚于 sEndDate),就以 MySQL 分片承载的天数为模数,对分片索引值求模得到所属分片;如果分片索引值早于 sBeginDate,就会被放到 defaultNode 分片上
与MyCat的类似分片算法对比
中间件
DBLE
MyCat
分片算法种类 date 分区算法 按日期(天)分片
两种中间件的取模范围分片算法使用上无差别
开发注意点
【分片索引】1. 必须是字符串,而且 java.text.SimpleDateFormat 能基于用户指定的 dateFormat 来转换成 java.util.Date
【分片索引】2. 提供带状模式和环状模式两种模式
【分片索引】3. 带状模式以 sBeginDate(含)起,以 86400000 毫秒(24 小时整)为一份,每 sPartionDay 份为一个分片,理论上分片数量可以无限增长,但是出现 sBeginDate 之前的数据而且没有设定 defaultNode 的话,会路由失败(如果有 defaultNode,则路由至 defaultNode)
【分片索引】4. 环状模式以 86400000 毫秒(24 小时整)为一份,每 sPartionDay 份为一个分片,以 sBeginDate(含)到 sEndDate(含)的时间长度除以单个分片长度得到恒定的分片数量,但是出现 sBeginDate 之前的数据而且没有设定 defaultNode 的话,会路由失败(如果有 defaultNode,则路由至 defaultNode)
【分片索引】5. 无论哪种模式,分片索引字段的格式化字符串 dateFormat 由用户指定
【分片索引】6. 无论哪种模式,划分不是以日历时间为准,无法对应自然月和自然年,且会受闰秒问题影响
运维注意点
【扩容】1. 带状模式中,随着 sBeginDate 之后的数据出现,分片数量的增加无需再平衡
【扩容】2. 带状模式没有自动增添分片的能力,需要运维手工提前增加分片;如果路由策略计算出的分片并不存在时,会导致失败
【扩容】3. 环状模式中,如果新旧 [sBeginDate,sEndDate] 之间有重叠,需要进行部分数据迁移;如果新旧 [sBeginDate,sEndDate] 之间没有重叠,需要数据再平衡
配置注意点
【配置项】1. 在 rule.xml 中,可配置项为 propertyname="sBeginDate" 、 propertyname="sPartionDay" 、 propertyname="dateFormat" 、 propertyname="sEndDate" 和 propertyname="defaultNode"
【配置项】2.在 rule.xml 中配置 propertyname="dateFormat",符合 java.text.SimpleDateFormat 规范的字符串,用于告知 DBLE 如何解析sBeginDate和sEndDate
【配置项】3.在 rule.xml 中配置 propertyname="sBeginDate",必须是符合 dateFormat 的日期字符串
【配置项】4.在 rule.xml 中配置 propertyname="sEndDate",必须是符合 dateFormat 的日期字符串;配置了该项使用的是环状模式,若没有配置该项则使用的是带状模式
【配置项】5.在 rule.xml 中配置 propertyname="sPartionDay",非负整数,该分片策略以 86400000 毫秒(24 小时整)作为一份,而 sPartionDay 告诉 DBLE 把每多少份放在同一个分片
【配置项】6.在 rule.xml 中配置 propertyname="defaultNode" 标签,非必须配置项,不配置该项的话,用户的分片索引值没落在 mapFile 定义
索引用于快速找到特定一些值的记录。如果没有索引,MySQL就必须从第一行记录开始读取整个表来检索记录。表越大,资源消耗越大。如果在字段上有索引的话,MySQL就能很快决定该从数据文件的哪个位置开始搜索记录,而无须查找所有的数据。如果表中有1000条记录的话,那么这至少比顺序地读取数据快100倍。注意,如果需要存取几乎全部1000条记录的话,那么顺序读取就更快了,因为这样会使磁盘搜索最少。
大部分MySQL索引(PRIMARY KEY, UNIQUE,INDEX 和 FULLTEXT)都是以B树方式存储。只有空间类型的字段使用R树存储,MEMORY (HEAP)表支持哈希索引。
字符串默认都是自动压缩前缀和后缀中的空格。
通常,如下所述几种情况下可以使用索引。哈希索引(用于 MEMORY 表)的独特之处在后面会讨论到。
想要尽快找到匹配 WHERE 子句的记录。
根据条件排除记录。如果有多个索引可共选择的话,MySQL通常选择能找到最少记录的那个索引。
做表连接查询时从其他表中检索记录。
想要在指定的索引字段 key_col 上找到它的 MIN() 或 MAX() 值。优化程序会在检查索引的
key_col 字段前就先检查其他索引部分是否使用了 WHERE key_part_# = constant 子句。这样的话,
MySQL会为 MIN() 或 MAX() 表达式分别单独做一次索引查找,并且将它替换成常数。当所有的表达式都被替换成常数后,查询就立刻返回。如下:
SELECT MIN(key_part2),MAX(key_part2) FROM tbl_name WHERE key_part1=10;
对表作排序或分组,当在一个可用的最左前缀索引上做分组或排序时(如 ORDER
BY key_part1, key_part2)。如果所有的索引部分都按照 DESC 排序,索引就按倒序排序。
有些时候,查询可以优化使得无需计算数据就能直接取得结果。当查询使用表中的一个数字型字段,且这个字段是索引的最左部分,则可能从索引树中能很快就取得结果:
SELECTkey_part3FROMtbl_nameWHEREkey_part1=1
假设有如下 SELECT 语句:
如果在 col1 和 col2 上有一个多字段索引的话,就能直接取得对应的记录了。