大数据量的查询,不仅查询速度非常慢,而且还会导致数据库经常宕机(刚接到这个项目时候,数据库经常宕机o(╯□╰)o)。 那么,如何处理上亿级的数据量呢?如何从数据库经常宕机到上亿数据秒查?仅以此篇文章作为处理的总结。

数据背景:
下面是存放历史数据表的数据量,数据量确实很大,3亿多条。但这也仅仅是测试数据而已,因为客户端服务器上的数据可能远不止于此。

为什么说远不止于此呢?实际情况是这样的:

有一个实时数据表,THTF_TABLE_AI,以及历史数据表,THTF_TABLE_AI_HIS

实时数据表固定3万条数据(客户推送过来的数据),每2小时刷新一次,每刷新一次就往历史表中插入一次数据。

可以算一下,历史表中数据量的数据量:

3 x 12 x 30 = 1080万,也就是每个月存储1080条数据,1年就1亿多的数据量。这样大的数据量,导致查询速度慢,估计用户会气炸的...

解决方案:
第一步:分表

如果历史表中存储了很多年的数据,会造成严重的数据冗余。那如果将历史表分表存储,比如每年创建一个表,数据存储到对应的年表中,必定会减少很多数据量。(如果分成年表数据量还是过大,可以细分到月表,天表...)。

我们这里以创建年表为例,写一个创建年表的存储过程,利用PLSQL定时任务定时执行此存储过程(定时每年12月31号创建下一年的年表)。存储过程如下,定时任务查看此篇文章:PLSQL执行Oracle定时任务

CREATE OR REPLACE
PROCEDURE CREATE_YEAR_TABLE IS
/*变量*/
grantSql VARCHAR2(50);
yearStr VARCHAR2(4);
tableCount int(2);
createSql VARCHAR2(1000);
BEGIN
/*权限*/
grantSql := 'grant create any table to thtf_taiyuan';
EXECUTE IMMEDIATE grantSql;
/*创建年表 注意create table 后边的空格*/
SELECT TO_CHAR(SYSDATE, 'yyyy')+1 INTO yearStr FROM dual;
createSql := 'CREATE TABLE ' || 'THTF_TABLE_YEAR_' || yearStr ||
'( SHE_SHI_CODE VARCHAR2(100),
SHE_SHI_TYPE NUMBER DEFAULT 1,
FEN_GONG_SI VARCHAR2(100),
SHUI_HAO NUMBER(20,4) DEFAULT 0,
PRE_SHUI_HAO NUMBER(20,4) DEFAULT 0,
DIAN_HAO NUMBER(20,4) DEFAULT 0,
PRE_DIAN_HAO NUMBER(20,4) DEFAULT 0,
RE_HAO NUMBER(20,4) DEFAULT 0,
PRE_RE_HAO NUMBER(20,4) DEFAULT 0,
SHI_JIAN DATE DEFAULT SYSDATE,
STATE NUMBER DEFAULT 1 )';
SELECT COUNT(1) INTO tableCount FROM user_tables WHERE table_name = CONCAT('THTF_TABLE_YEAR_', yearStr);
IF tableCount = 0 THEN
EXECUTE IMMEDIATE createSql;
COMMIT;
END IF;
END CREATE_YEAR_TABLE;
第二步:分区

年表创建过后,查询就是查询年表中的数据,可是虽然分表了,但是年表中的数据量仍然很大,查询速度虽然有提升,但并不能满足用户的要求。便考虑到分表再分区,即将历史数据以不同的年表来存储,在年表中按月分区。

说道分区,要恶补一下了~

数据库分区:就是减少SQL操作的数据量,从而提升查询效率。表分区后,逻辑上仍然是一张表,只不过将表中的数据在物理上存放到多个表空间上。这样在查询数据时,会查询相应分区的数据,避免了全表扫描。

分区又分为水平分区、垂直分区。

水平分区:就是对行进行分区,举个例子来说,就是一个表中有1000万条数据,每100万条数据划一个分区,这样就将表中数据分到10个分区中去。水平分区要通过某个特定的属性列进行分区,比如我用的列就是Date时间。

垂直分区:通过对标垂直划分来减少表的宽度,从而提升查询效率。比如一个学生表中,有他相关的信息列,还有论文列以CLOB存储。这些以CLOB存储的论文并不会经常被访问到,这时候就要把这些不经常使用的CLOB划分到另一个分区,需要访问时再调用它。

总的来说,分区的主要目的还是避免了全表扫描,从而提升查询速度。

接下来在上面的存储过程的基础上,我们创建按月分区。

CREATE OR REPLACE
PROCEDURE CREATE_YEAR_TABLE IS
grantSql VARCHAR2(50);
yearStr VARCHAR2(4);
tableCount int(2);
createSql VARCHAR2(1000);
BEGIN
/*权限*/
grantSql := 'grant create any table to thtf_taiyuan';
EXECUTE IMMEDIATE grantSql;
/*创建年表 注意create table 后边的空格*/
SELECT TO_CHAR(SYSDATE, 'yyyy')+1 INTO yearStr FROM dual;
createSql := 'CREATE TABLE ' || 'THTF_TABLE_YEAR_' || yearStr ||
'( SHE_SHI_CODE VARCHAR2(100),
SHE_SHI_TYPE NUMBER DEFAULT 1,
FEN_GONG_SI VARCHAR2(100),
SHUI_HAO NUMBER(20,4) DEFAULT 0,
PRE_SHUI_HAO NUMBER(20,4) DEFAULT 0,
DIAN_HAO NUMBER(20,4) DEFAULT 0,
PRE_DIAN_HAO NUMBER(20,4) DEFAULT 0,
RE_HAO NUMBER(20,4) DEFAULT 0,
PRE_RE_HAO NUMBER(20,4) DEFAULT 0,
SHI_JIAN DATE DEFAULT SYSDATE,
STATE NUMBER DEFAULT 1 )
/*按月分区*/
PARTITION BY RANGE(SHI_JIAN)
INTERVAL(NUMTOYMINTERVAL(1,''' || 'MONTH' || '''))
( PARTITION PART1 VALUES LESS THAN(TO_DATE('''|| CONCAT(yearStr, '-11-01') ||''','''|| 'YYYY-MM-DD' ||''')) )';
SELECT COUNT(1) INTO tableCount FROM user_tables WHERE table_name = CONCAT('THTF_TABLE_YEAR_', yearStr);
IF tableCount = 0 THEN
EXECUTE IMMEDIATE createSql;
--添加注释
EXECUTE IMMEDIATE 'COMMENT ON COLUMN ' || 'THTF_TABLE_YEAR_' || yearStr || '.SHE_SHI_CODE IS ''设施编号''';
EXECUTE IMMEDIATE 'COMMENT ON COLUMN ' || 'THTF_TABLE_YEAR_' || yearStr || '.SHE_SHI_TYPE IS ''设施类型''';
EXECUTE IMMEDIATE 'COMMENT ON COLUMN ' || 'THTF_TABLE_YEAR_' || yearStr || '.FEN_GONG_SI IS ''分公司''';
EXECUTE IMMEDIATE 'COMMENT ON COLUMN ' || 'THTF_TABLE_YEAR_' || yearStr || '.SHUI_HAO IS ''水耗''';
EXECUTE IMMEDIATE 'COMMENT ON COLUMN ' || 'THTF_TABLE_YEAR_' || yearStr || '.PRE_SHUI_HAO IS ''上一小时水耗''';
EXECUTE IMMEDIATE 'COMMENT ON COLUMN ' || 'THTF_TABLE_YEAR_' || yearStr || '.DIAN_HAO IS ''电耗''';
EXECUTE IMMEDIATE 'COMMENT ON COLUMN ' || 'THTF_TABLE_YEAR_' || yearStr || '.PRE_DIAN_HAO IS ''上一小时电耗''';
EXECUTE IMMEDIATE 'COMMENT ON COLUMN ' || 'THTF_TABLE_YEAR_' || yearStr || '.RE_HAO IS ''热耗''';
EXECUTE IMMEDIATE 'COMMENT ON COLUMN ' || 'THTF_TABLE_YEAR_' || yearStr || '.PRE_RE_HAO IS ''上一小时热耗''';
EXECUTE IMMEDIATE 'COMMENT ON COLUMN ' || 'THTF_TABLE_YEAR_' || yearStr || '.SHI_JIAN IS ''时间''';
EXECUTE IMMEDIATE 'COMMENT ON COLUMN ' || 'THTF_TABLE_YEAR_' || yearStr || '.STATE IS ''状态值''';
COMMIT;
END IF;
END CREATE_YEAR_TABLE;
如果分区要细化到天,将分区语句改为如下:

PARTITION BY RANGE(SHI_JIAN)
INTERVAL(NUMTOYMINTERVAL(1,''' || 'DAY' || '''))
( PARTITION PART1 VALUES LESS THAN(TO_DATE('''|| CONCAT(yearStr, '-01-01') ||''','''|| 'YYYY-MM-DD' ||''')) )';
创建完分区后,如何查询表中有哪些分区呢?

--查分区数
SELECT table_name,partition_name from user_tab_partitions where table_name = 'THTF_TABLE_YEAR_2017'
如何查询分区中的数据呢?

--查分区数据
SELECT * FROM THTF_TABLE_YEAR_2017 PARTITION(PART1)
 
---------------------
作者:_Rt
来源:CSDN
原文:https://blog.csdn.net/rongtaoup/article/details/82457544
版权声明:本文为博主原创文章,转载请附上博文链接!

Oracle亿级数据查询处理(数据库分表、分区实战)的更多相关文章

  1. 基于Mysql数据库亿级数据下的分库分表方案

    移动互联网时代,海量的用户数据每天都在产生,基于用户使用数据的用户行为分析等这样的分析,都需要依靠数据都统计和分析,当数据量小时,问题没有暴露出来,数据库方面的优化显得不太重要,一旦数据量越来越大时, ...

  2. 数据库分表分区后的ID生成之雪花生成

    转自https://www.cnblogs.com/jajian/p/11101213.html 传统的单体架构的时候,我们基本是单库然后业务单表的结构.每个业务表的ID一般我们都是从1增,通过AUT ...

  3. MySQL数据库分表分区(一)(转)

    面对当今大数据存储,设想当mysql中一个表的总记录超过1000W,会出现性能的大幅度下降吗? 答案是肯定的,一个表的总记录超过1000W,在操作系统层面检索也是效率非常低的   解决方案: 目前针对 ...

  4. Oracle学习(十四)分表分区

    一.前言 大数据量的查询,不仅查询速度非常慢,而且还会导致数据库经常宕机,在尝试添加索引及查询方式修改后,还有没有更有效的解决方案呢? 分库.分表.分区这些概念咱就应该了解一下. 二.分表 假如一个大 ...

  5. 阅读之MySQL数据库分表

    移动互联网时代,海量的用户数据每天都在产生,基于用户使用数据等这样的分析,都需要依靠数据统计和分析,当数据量小时,数据库方面的优化显得不太重要,一旦数据量越来越大,系统响应会变慢,TPS直线下降,直至 ...

  6. MySQL数据库分表的3种方法

    原文地址:MySQL数据库分表的3种方法作者:dreamboycx 一,先说一下为什么要分表 当一张的数据达到几百万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了.分表的目 ...

  7. zabbix 数据库分表操作

    近期zabbix数据库占用的io高,在页面查看图形很慢,而且数据表已经很大,将采用把数据库的数据目录移到新的磁盘,将几个大表进行分表操作 一.数据迁移: 1.数据同步到新的磁盘上,先停止mysql(不 ...

  8. mysql 查询指定数据库所有表, 指定表所有列, 指定列所有表 所有外键及索引, 以及索引的创建和删除

    查询指定 数据库 中所有 表 (指定数据库的,所有表) // 可以把 TABLE_NAME 换成 * 号, 查看更丰富的信息 SELECT TABLE_NAME FROM information_sc ...

  9. mysql 数据库 分表后 怎么进行分页查询?Mysql分库分表方案?

    Mysql分库分表方案 1.为什么要分表: 当一张表的数据达到几千万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了.分表的目的就在于此,减小数据库的负担,缩短查询时间. m ...

随机推荐

  1. MySQL死锁查询【原创】

    死锁详情查询 SELECT SUM(trx_rows_locked) AS rows_locked, SUM(trx_rows_modified) AS rows_modified, SUM(trx_ ...

  2. 利用微信企业号的告警功能,联动检测ICMP的shell脚本

    作者:邓聪聪 由于设备IP众多,为了及时发现IP地址有不可达现象,利用微信的联动报警,及时发现问题,以下是脚本内容!!! ping.sh #!/bin/bash ###SCRIPT_NAME:icmp ...

  3. mq for aix 清理步骤

    删除所有相关进程smit remove 删除mq删除mqm用户和用户组 如果unmount /cdrom 卸载不掉的话使用 fuser -xcu /cdrom rm /var/mqm

  4. Linux 网络侦错:无法联机原因分析

    所谓的软件问题,绝大部分就是 IP 参数设定错误啊,路由不对啊,还有 DNS 的 IP 设定错误等等的, 这些问题都是属于软件设定啦!只要将设定改一改,利用一些侦测软件查一查,就知道问题出在哪里了!基 ...

  5. P1262 间谍网络 (tarjan缩点 水过去)

    题目描述 由于外国间谍的大量渗入,国家安全正处于高度的危机之中.如果A间谍手中掌握着关于B间谍的犯罪证据,则称A可以揭发B.有些间谍收受贿赂,只要给他们一定数量的美元,他们就愿意交出手中掌握的全部情报 ...

  6. Alpha 冲刺 (5/10)

    目录 摘要 团队部分 个人部分 摘要 队名:小白吃 组长博客:hjj 作业博客:冲刺5 团队部分 后敬甲(组长) 过去两天完成了哪些任务 文字描述 最近事情有点多,只是跟进了下进度,写了写博客 接下来 ...

  7. 制作缩略图java工具类

    import java.awt.Image; import java.awt.image.BufferedImage; import java.io.File; import java.io.File ...

  8. mysql 5.6升级到5.7.22

    下载对应的包 wget  https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7.22-linux-glibc2.12-x86_64.tar 备份数据 ...

  9. Sublime Text3 C++ 设置

    系统环境: 首先是 C++ 的环境设置, 先下载 CodeBlocks, 安装目录下有 MinGW, 直接复制到 C 盘下, 再在电脑中添加 环境变量(PATH). Sublime Text3 设置: ...

  10. liunx 安装redis 4.0

    liunx 上安装redis 4.0.1 第一步:将 redis-4.0.1.tar.gz 压缩问上传至/home目录下 第二步: 解压文件  tar -zxvf  redis-4.0.1.tar.g ...