精华内容
下载资源
问答
  • 千万级数据处理

    千次阅读 2018-11-12 22:23:06
    千万级数据处理 前言     近日一次版本上线时,涉及到千万级数据处理,因一时疏漏造成Oracle数据库回滚段爆掉,造成版本重复发布。  &...

    千万级数据处理

    前言

        近日一次版本上线时,涉及到千万级数据处理,因一时疏漏造成Oracle数据库回滚段爆掉,造成版本重复发布。

        系统日常运行中,产生部分历史数据,这些数据不能删除。日积月累情况下,出现超级大的数据量。

    • 需要将客户信息历史表中客户性别为女性,出生日期在90年以前的客户存放至另一张表。目前客户信息历史表的数据量高达9000多万。

    如下SQL在执行过程:耗时40多分钟,后续变更处理方式后,耗时4-5分钟。数据库回滚段使用5G左右空间。

    --执行SQL如下,table_cust_history该表数据量高达9000多万。
    insert into table_temp
    select ... from table_cust_history
     where sex=''
       and birthday < ''; 
       
    SQl分析:
    1. 首先分析查询,因数据量大,查询条件必须走索引,才能保证查询速度
    2. 耗时40分钟的原因是,我们在创建table_temp表的时候,惯性思维给该表加的相应字段的索引,导致没插入一条数据,索引都要变动,耗时就上去了
    3. 正确的做法应该为:删除索引(主键索引要保留),插入数据,再加入索引。最后加索引耗时仅需几分钟。
    
    --执行如下删除SQl  删除1150万左右的数据,耗时20分钟 
    delete from table_cust_history
    where exists( select 1 from table_temp where '条件' )
    
    SQL分析:两张表的关联条件必须要有索引,
    
    耗时比上面SQL长,是因为这个SQL要查询多次,子查询的条件查询,删除时条件查询。
    
    

    因业务逻辑更新,需要初始化表中的数据。需要初始化的数据为4000多万。
    执行SQl更新字段包含一个带索引的字段。耗时40分钟,回滚段使用了19-20G。

    总结:索引不仅仅提升了查询的效率,同时也会降低大数据量存储更新的效率

    1. 若遇见千万级的数据查询,一定要使用索引字段限制数据量。
    2. 大数据量更新,插入数据时,建议删除无关紧要的索引,等数据操作完毕后,再加入索引。
    3. 操作千万级数据时,应提前看一下数据库回滚段设置大小。如果可以尽量大些。

    千辛万苦,熬到半夜,吸取经验,记得教训。

    希望能给前赴后继的小伙伴带来帮助。

    展开全文
  • 采用POI、JXL框架导出CVS文件,支持千万级数据导出,无内存溢出,自己项目中使用中。
  • MySQL千万级数据处理

    万次阅读 多人点赞 2018-08-14 17:51:35
    目录 第一篇,优化篇 第二篇,案例篇 第一篇,优化篇 ...除非单表数据未来会...而事实上很多时候MySQL单表的性能依然有不少优化空间,甚至能正常支撑千万级以上的数据量: 字段 1、尽量使用TINYINT、SMALLIN...

    目录

     

    第一篇,优化篇

    第二篇,案例篇


    第一篇,优化篇

    单表优化

    除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分,拆分会带来逻辑、部署、运维的各种复杂度,一般以整型值为主的表在千万级以下,字符串为主的表在五百万以下是没有太大问题的。而事实上很多时候MySQL单表的性能依然有不少优化空间,甚至能正常支撑千万级以上的数据量:

    字段

    1、尽量使用TINYINT、SMALLINT、MEDIUM_INT作为整数类型而非INT,如果非负则加上UNSIGNED

    2、VARCHAR的长度只分配真正需要的空间

    3、使用枚举或整数代替字符串类型

    4、尽量使用TIMESTAMP而非DATETIME,

    5、单表不要有太多字段,建议在20以内

    6、避免使用NULL字段,很难查询优化且占用额外索引空间

    7、用整型来存IP

    索引

    索引的种类:

    1、主键索引 (把某列设为主键,则就是主键索引)

    2、唯一索引(unique) (即该列具有唯一性,同时又是索引)

    3、index (普通索引)

    4、全文索引(FULLTEXT)

    5、复合索引(多列和在一起)

    索引建立注意事项:

    1、索引并不是越多越好,要根据查询有针对性的创建,考虑在WHERE和ORDER BY命令上涉及的列建立索引,可根据EXPLAIN来查看是否用了索引还是全表扫描

    2、应尽量避免在WHERE子句中对字段进行NULL值判断,否则将导致引擎放弃使用索引而进行全表扫描如:select id from t where num is null 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:select id from t where num = 0

    3、值分布很稀少的字段不适合建索引,例如"性别"这种只有两三个值的字段

    4、字符字段只建前缀索引

    5、并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段 sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。

    6、应尽可能的避免更新 clustered 索引数据列,因为 clustered 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新 clustered 索引数据列,那么需要考虑是否应将该索引建为 clustered 索引。

    7、应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。

    8、尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:select id from t where num = 10 or num = 20

    可以这样查询: 

    select id from t where num = 10 

    union all 

    select id from t where num = 20

    9、下面的查询也将导致全表扫描:select id from t where name like ‘%abc%’

    若要提高效率,可以考虑全文检索。

    10、in 和 not in 也要慎用,否则会导致全表扫描,如:select id from t where num in(1,2,3) 

    对于连续的数值,能用 between 就不要用 in 了: 

    select id from t where num between 1 and 3

    11、如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:select id from t where num = @num 

    可以改为强制查询使用索引: 

    select id from t with(index(索引名)) where num = @num

    12、不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。如:select id from t where num / 2 = 100 

    select id from t where substring(name, 1 ,3) = ’abc’查询name以abc开头的id列表

    分别应改为: 

    select id from t where num = 100 * 2

    select id from t where name like ‘abc%’ 

    13、在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。

    14、很多时候用 exists 代替 in 是一个好的选择:select num from a where num in(select num from b) 

    用下面的语句替换: 

    select num from a where exists(select 1 from b where num = a.num)

    引擎

    目前广泛使用的是MyISAM和InnoDB两种引擎:

    MyISAM:

    MyISAM引擎是MySQL 5.1及之前版本的默认引擎,它的特点是:

    • 不支持行锁,读取时对需要读到的所有表加锁,写入时则对表加排它锁
    • 不支持事务
    • 不支持外键
    • 不支持崩溃后的安全恢复
    • 在表有读取查询的同时,支持往表中插入新纪录
    • 支持BLOB和TEXT的前500个字符索引,支持全文索引
    • 支持延迟更新索引,极大提升写入性能
    • 对于不会进行修改的表,支持压缩表,极大减少磁盘空间占用
    • 创建一张表,对会应三个文件, *.frm 记录表结构, *.myd 数据, *.myi 索引文件

    InnoDB:

    InnoDB在MySQL 5.5后成为默认索引,它的特点是:

    • 支持行锁,采用MVCC来支持高并发
    • 支持事务
    • 支持外键
    • 支持崩溃后的安全恢复
    • 不支持全文索引
    • 创建一张表,对会应一个文件 *.frm,数据存放到ibdata1

    总体来讲,MyISAM适合SELECT密集型的表,而InnoDB适合INSERT和UPDATE密集型的表

    其他注意事项:

    1、AND型查询要点(排除越多的条件放在前面):假设要查询满足条件A,B和C的文档,满足A的文档有4万,满足B的有9K,满足C的是200,那么应该用C and B and A 这样只需要查询200条记录。

    2、OR型查询要点(符合越多的条件放在前面):OR型查询与AND查询恰好相反,匹配最多的查询语句放在最前面。

    3、查询数据不建议使用 select * from table ,应用具体的字段列表代替“*”,不要返回用不到的无关字段,尤其是大数据列。

    4、在分页查询中使用 limit关键字时,应重复考虑使用索引字段来筛选来避免全表扫描,如:

    select c1, c2, c3 from table order by id asc limit 100, 100

    应尽量配合where条件来使用(大数据量情况查询效率提升10倍):

    select c1, c2, c3 from table where id > 100 order by id asc limit 0, 100

    5、在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先 create table,然后再insert。

    6、如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。但是,避免频繁创建和删除临时表,以减少系统表资源的消耗。

    7、尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。因此,使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。

    8、与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。

    9、在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF 。无需在执行存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。

    10、为提高系统并发能力,应尽量避免大事务操作,尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。

    参数调优:

    wait_timeout:

    数据库连接闲置时间(长连接),闲置连接会占用内存资源。可以从默认的8小时减到半小时。

    max_user_connection:

    最大连接数,默认为0(无上限),最好设一个合理上限。

    thread_concurrency:

    并发线程数,设为CPU核数的两倍。

    key_buffer_size:

    索引块的缓存大小,增加会提升索引处理速度,对MyISAM表性能影响最大。对于内存4G左右,可设为256M或384M,通过查询show status like 'key_read%',保证key_reads / key_read_requests在0.1%以下最好

    innodb_buffer_pool_size:

    缓存数据块和索引块,对InnoDB表性能影响最大。通过查询 show status like 'Innodb_buffer_pool_read%',

    保证 (Innodb_buffer_pool_read_requests – Innodb_buffer_pool_reads) / Innodb_buffer_pool_read_requests 越高越好

    read_buffer_size:

    MySql读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySql会为它分配一段内存缓冲区。如果对表的顺序扫描请求非常频繁,可以通过增加该变量值以及内存缓冲区大小提高其性能

    sort_buffer_size:

    MySql执行排序使用的缓冲大小。如果想要增加ORDER BY的速度,首先看是否可以让MySQL使用索引而不是额外的排序阶段。如果不能,可以尝试增加sort_buffer_size变量的大小

    其他参数

    读写分离

    也是目前常用的优化,从库读主库写,一般不要采用双主或多主引入很多复杂性,尽量采用文中的其他方案来提高性能。同时目前很多拆分的解决方案同时也兼顾考虑了读写分离。

    分库分表

    水平拆分

    垂直拆分

    升级硬件

    根据MySQL是CPU密集型还是I/O密集型,通过提升CPU和内存、使用SSD,都能显著提升MySQL性能。

    缓存应用

    MySQL内部:

    在系统调优参数介绍了相关设置

    数据访问层:

    比如MyBatis针对SQL语句做缓存,而Hibernate可以精确到单个记录,这里缓存的对象主要是持久化对象 Persistence Object

    应用服务层:

    这里可以通过编程手段对缓存做到更精准的控制和更多的实现策略,这里缓存的对象是数据传输对象Data Transfer Object

    Web层:针对web页面做缓存

    用户端的缓存:

    可以根据实际情况在一个层次或多个层次结合加入缓存。这里重点介绍下服务层的缓存实现,目前主要有两种方式:1、直写式(Write Through):在数据写入数据库后,同时更新缓存,维持数据库与缓存的一致性。这也是当前大多数应用缓存框架如Spring Cache的工作方式。这种实现非常简单,同步好,但效率一般。2、回写式(Write Back):当有数据要写入数据库时,只会更新缓存,然后异步批量的将缓存数据同步到数据库上。这种实现比较复杂,需要较多的应用逻辑,同时可能会产生数据库与缓存的不同步,但效率非常高。


    第二篇,案例篇

    实际案例:

    比如针对 1000w 条老数据加密处理

    解决的思路:

    查询优化 + 内存调优 + 分批处理 + 高效数据源 + 多线程(线程池) + 反复调试

    考虑客观因素:

    硬件设施、网络宽带

    假设1000w,分配20个线程,每页1万条

    则分页总数:1000 / 1 = 1000页

    线程平均处理分页数:(int)Math.floor(1000 / 20) = 50页

    线程处理最大分页数:50页 + 1000 % 20 = 50页

    则第一个线程处理 1 - 20页,

    第二个线程处理 21- 40页,

    第三个线程处理 41- 60页,

    ...

    依次内推,第三十个线程,处理981 - 1000页

    代码片段:

        /**
         * maysql 多线程 + 连接池,分页查询 + 批量更新示例
         * 注意:limit 参数不支持使用占位符?
         *
         * 10个线程,60万条数据,每页1w条,进行批量更新总耗时:53558毫秒,约0.90分钟(Where条件 + Limit N )
         * 20个线程,60万条数据,每页1w条,进行批量更新总耗时:53558毫秒,约0.89分钟(Where条件 + Limit N )
         * 20个线程,200万条数据,每页1w条,进行批量更新总耗时:160132毫秒,约2.67分钟(Where条件 + Limit N )
         * 40个线程,200万条数据,每页1w条,进行批量更新总耗时:199220毫秒,约3.32分钟(Where条件 + Limit N )
         *
         * 截止4月27日finance_ant_loan数据库数据:
         * LendingDetail, 总记录数 8729
         * LoanDetail, 总记录数 550417
         *
         * 截止4月27日finance_jd_loan数据库数据:
         * CUS, 总记录数 1006179
         * Loan,总记录数 32395990
         */
        @Test
        public void testMultiThreadBatchUpdate2(){
            Long beginTime = System.currentTimeMillis();
            int pageSize = 10000;
            int threads = 20;
            int resultCount = findCount();
    
            if (resultCount <= 0){
                log.info("未找到符合条件的记录!");
                return;
            }
    
            int pageTotal = (resultCount % pageSize == 0) ? (resultCount / pageSize) :  ((int)Math.floor(resultCount / pageSize) + 1);
            log.info("查询出数据库总计录数:{}", resultCount);
            log.info("每页数量:{}", pageSize);
            log.info("分页总数:{}", pageTotal);
    
            threads = getActualThreads(pageTotal, threads);
            int avgPages = (int)Math.floor(pageTotal / threads);
            int restPages = pageTotal % threads;
            log.info("子线程数:{}", threads);
            log.info("子线程平均处理分页数:{}", avgPages);
            log.info("子线程处理最大分页数:{}", avgPages + restPages);
    
            MultiThreadHandler handler = new MultiParallelThreadHandler();
            for (int i = 0; i < threads; i++){
                int fromPage = i * avgPages + 1;
                int endPage = i * avgPages + avgPages;
    
                if (i == threads - 1) {
                    endPage = endPage + restPages;
                }
    
                String threadName = "thread" + (i + 1);
                log.info("Query child thread:{} process paging interval: [{}, {}]", threadName, fromPage, endPage);
                handler.addTask(new TestThread2(fromPage, endPage, pageSize));
            }
    
            try {
                handler.run();
            } catch (ChildThreadException e) {
                log.error(e.getAllStackTraceMessage());
            }
    
            log.info("【分页查询+批量更新】结束,受影响总记录数:{},总耗时:{}毫秒", resultCount, System.currentTimeMillis() - beginTime);
        }
    
        private int findCount(){
            Connection connection = AntConnPool.getConnection();
            PreparedStatement preparedStatement;
    
            try {
                preparedStatement = connection.prepareStatement("SELECT COUNT(1) FROM test2 WHERE 1 = 1");
                ResultSet resultSet = preparedStatement.executeQuery();
                if (resultSet.next()){
                    return resultSet.getInt(1);
                }
            }catch (Exception e){
                e.printStackTrace();
                log.error("数据库操作异常!!!");
            }finally {
                ConnMgr.closeConn(connection);
            }
            return 0;
        }
    
        /**
         * @description 获得实际线程数
         * @author Zack
         * @date 15:28 2018/5/7
         * @param pageTotal
         * @param threads
         * @return int
         */
        private int getActualThreads(final int pageTotal, final int threads){
            if ((int)Math.floor(pageTotal / threads) < 1 && threads > 1){
                return getActualThreads(pageTotal, threads - 1);
            }
            return threads;
        }
    /**
     * @description 多线程处理分页
     * @author Zack
     * @date 2018/4/27
     * @version 1.0
     */
    @Slf4j
    public class TestThread2 extends MysqlParallelThread{
    
        public TestThread2(int fromPage, int endPage, int pageSize){
            super(fromPage, endPage, pageSize);
        }
    
        @Override
        public void run() {
            log.info("Query child thread:{} process paging interval: [{}, {}] started.", Thread.currentThread().getName(), getFromPage(), getEndPage());
            Long beginTime = System.currentTimeMillis();
            int maxId = 0;
            int fromIndex = (getFromPage() - 1) * getPageSize();
            Connection connection = AntConnPool.getConnection();
    
            try{
                for (int pageNo = getFromPage(); pageNo <= getEndPage(); pageNo++){
                    if (maxId != 0){
                        fromIndex = 0;
                    }
                    maxId = batchUpdate(findList(connection, fromIndex, maxId), pageNo);
                }
            }catch (Exception e){
                throw new RuntimeException(Thread.currentThread().getName() + ": throw exception");
            }finally {
                ConnMgr.closeConn(connection);
                log.info("Query child thread:{} process paging interval: [{}, {}] end. cost:{} ms.", Thread.currentThread().getName(), getFromPage(), getEndPage(), (System.currentTimeMillis() - beginTime));
            }
        }
    
        private ResultSet findList(Connection connection, int fromIndex, int maxId){
            try {
                PreparedStatement preparedStatement = connection.prepareStatement("SELECT id, name, total FROM test2 WHERE id > ? ORDER BY id ASC limit "+fromIndex+", " + getPageSize(), ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
                preparedStatement.setInt(1, maxId);
                return preparedStatement.executeQuery();
            }catch (Exception e){
                e.printStackTrace();
                log.error("数据库操作异常!!!");
            }
            return null;
        }
    
        private int batchUpdate(ResultSet resultSet, int pageNo) {
            Long beginTime = System.currentTimeMillis();
            Connection connection = AntConnPool.getConnection();
            PreparedStatement preparedStatement;
    
            try {
                connection.setAutoCommit(false);
                preparedStatement = connection.prepareStatement("UPDATE test2 SET name = ?, total = ? WHERE id = ?");
    
                if (Objects.isNull(resultSet) || resultSet.wasNull()){
                    log.info("查询第{}页数据为空!", pageNo);
                    return 0;
                }
    
                while (resultSet.next()){
                    // 加密处理
                    preparedStatement.setString(1, SecUtil.encryption(resultSet.getString(2)));
                    preparedStatement.setInt(2, resultSet.getInt(3) + 1);
                    preparedStatement.setInt(3, resultSet.getInt(1));
                    preparedStatement.addBatch();
                }
    
                int[] countArray = preparedStatement.executeBatch();
                connection.commit();
    
                // 游标移至最后一行
                resultSet.last();
                int maxId = resultSet.getInt(1);
                log.info("子线程{}批量更新MYSQL第{}页结束,maxId:{}, 受影响记录数:{},耗时:{}毫秒", Thread.currentThread().getName(), pageNo, maxId, countArray.length, System.currentTimeMillis() - beginTime);
                return maxId;
            }catch (Exception e){
                e.printStackTrace();
                log.error("数据库操作异常!!!");
            }finally {
                ConnMgr.closeConn(connection);
            }
            return 0;
        }
    }

    总结

    使用多线程合理分配执行任务,避免数据重复执行和漏执行。

     

    扩展阅读

    https://dev.mysql.com/doc/refman/8.0/en/optimization.html

     

     

     

     

     

     

     

     

     

     

    展开全文
  • 浅谈--数据库 SQL千万级数据处理解决方案

    万次阅读 多人点赞 2016-07-05 11:57:27
    在这个大数据兴起的时代,过亿条的数据处理已经不少见了。以至于一个处理过程要几个小时的。后面慢慢优化,查找一些经验文章。才学到了一些基本方法。分享一下,由于不是专业的DBA,可能不是最优的解决方案,共同...

    在这个大数据兴起的时代,过亿条的数据的处理已经不少见了。以至于一个处理过程要几个小时的。后面慢慢优化,查找一些经验文章。才学到了一些基本方法。分享一下,由于不是专业的DBA,可能不是最优的解决方案,共同学习和探讨吧...

    1. 数据太多。放在一个表肯定不行。 

    比如月周期表。一个月1000万,一年就1.2亿,如此累计下去肯定不行的。所以都是基于一个周期数据一个表。甚至一个周期数据就要分几个分表。主要是考虑实际的数据量而定。当你创建一个新表时,可能这个表需要有索引,但是都要先取消索引,或者先建立表,导入数据后,再建立索引。 

    必要时处理完,统计完后,就备份到磁带或者其他介质。然后清掉。 

    从问题域来看,一个周期内的数据关联性最大。比如统计一个客户某个帐期的话单总额,同比上月增幅,还有就是零话费客户等。如此种种,参照的数据不外乎本周期,或者两个周期,甚至更多就是一个季度,或者半年的样子(类似三个月连续零话费,或者三个月连续欠费未交之类的,保存量之类的报表可能会要一年的数据)。而且这样的情况在数据挖掘或者高级管理报表中比较常见,一般营业部门使用的界面中,是不可能含有这样的统计的。 

    所以数据按表分开,甚至于可以按数据库分开,更便于管理。 

    大家要打消一种固有的思路,这些数据,跟环卫工人处理垃圾一样,是几乎有点带人工处置的多步骤方式,也就是不会作为常规数据(如客户基本资料等)长期存在和频繁使用的。所以我们可以改变思路,就是想尽办法,在需要的时候,做最佳处理,而在不需要时,清理掉它。也就是说,比如分表,你可以分100个表,1000个表都可以。只要方便统计和得到所需数据即可。 

    view只是说你能在写select语句时简单一点,对速度没有任何提高。 

    主要是,你的分表的方式能建立减少访问所有数据,就能提高速度。比如你做某个统计,那些数据恰好在某个分表内。举例说,你有10个分部,而你统计id=1这个分部时,你恰好把数据放在第一个分表里,你就可以在存储器内通过判断,只访问第一个分表,从而提高统计速度。如果你的统计需要统计全部分表内的数据,那处理速度还是一样慢。 

    2. 假设每个表的数据在数十万条,那统计起来是没有任何瓶颈的。常规的数据库都应该没任何问题。 

    3. 预处理的必要性。 

    有人问:我统计一千万条数据汇总,要多久多久,能否提高。。。试想你把中国人所有的存款加总,需要多长时间吧?看看这个问题的规模,其实再复杂的数据库dbms,我们说他都逃不过:找出符合条件的数据,一条一条的加总这个计算过程。暂且不提where条件了。预处理的必要性在于,如此规模的数据处理,本身就是一个非常耗时的过程,我们有必要提前,处理其结果到一个表内,或者多个表里面。用户查询时,再显示出来。比如说1000万数据分10个分部,要看每个分部的应收增长,那我们可以预先统计数据到分部费用表中,则用户端报表显示时,就非常快。如果任何数据汇总都要从原始数据去统计,那是不现实的。所以我们可以设置原始数据表,中间结果表,结果表,汇总表,月结表,期间表之类的东西。逐步统计归属。 

    另外要提的是,这样的动作肯定非常耗时,而且!这样的数据如果由服务器的存储过程定期定时执行的话,处理的规模就只有一次,任何客户端,都只从结果表里产生报表。如果不用此方法,任何客户端报表都从原始数据产生,理论上是可以,但是这样的千万条数据汇总的处理会做N次。而且时间上也是不容许的。 


    还有,这样的统计过程最好是分开db进行存放,而公用的数据比如客户基本资料,最好拷贝一份到这个新db中来处理。这样可以不干扰到正常的使用。 

    可以在晚上,或者另开db或者在另外的server上跑这个过程。处理完后,写一个标志告诉主db,则客户端可以统计这些报表了。 

    4. 对单行数据做计算字段。举个例子,比如一条记录的产生时间是2016-01-01 12:00:00.001,如果你的统计刚好需要对某个时段进行统计,那最好增加字段,比如hour字段,下一个批处理命令下去,取得小时数,然后再统计。 


    5. select语句中忌讳对column做函数。因为函数将导致查询条件不走索引,而改走遍历所有数据。这样你就是查一条数据,也会遍历所有数据,那岂不是可怜。 


    6. 条件尽量都是数字,也就是都用id,比如分部,镇区,业务种类,接入类型,客户地址,等等,都需要用到fk方式的编码,主表里只用数字id,请记住是数字型id。整数型数字是计算最快的数据类型。如果金额极大,可以用decimal(小数=0)。varchar类型是效率很低的,不过好像有sql的md5算法,我想可以尝试这个方法(我还没试过)。 


    7. 索引,这个是海量数据查询首要解决的问题。 

    没有索引,就是遍历。索引没有覆盖到,也会走遍历。 


    8. 复杂的统计,用存储器做分步处理,然后得到结果,同比一条select语句实现要轻松和明白得多。 

    而且对表的占用时间要短得多。当然,很复杂的统计可能要用到条件判断,循环等,一条select语句是无法处理的。多层的where中的子句也是效率低,容易占用表的写法。 

    原则上,这里我所讨论的问题都不是那种基于网站内容管理的小case,主要对企业运用而言。比如举例说查一个“存量客户增幅表”,问题都不是简单到直接对比两个月的话费总额这么简单,还得找出之前他的话费如何,比如超过多少钱的才列入统计对象。所以,我的理解:复杂的问题,必须存储过程。真正做过几个项目才会明白,写sql语句会比编程代码还要多。真正的程序,其实是sql。 

    最后说一句,如果经验足够丰富,写出的统计过程,其执行时间在数分钟甚至几个小时都是正常的。所以初学者应该明白,数据量是与处理时间成正比的。如果平时处理几条数据感觉很快,数据量猛然增加几个数量级,不要认为时间上还能优化到几秒钟。 


    ERP里的MRP展开计算,通常能到几个小时的。这都是正常的。(主要是物料多,bom多,计算步骤太多造成) 

    9. 补充一点。如果数据量超过我们标题的千万级,甚至几十亿数量级。那也不存在问题,还是分而治之的思路,就是把数据在多台服务器上并行运行。就好像为灾区捐款一样,靠一个人的力量是不行的。人多力量大。类似数据分拣之类的,只需要原始数据和基本资料,还有一些计费策略之类的。完全可以分布在多台server上同时处理,也是必要的。主要根据你的数据量和单台处理的速度以及你要求的总的处理时间而决定的。有人说select语句难道也需要分布?只能说,如果确实有必要,也能做到。比如你要返回所有话单异常的数据,那也可以从每台执行检索,然后汇合到一起,我想是可以的。 

    总而言之: 

    一。合理设计表结构,使得统计汇总最高效(包括fk设计和用数字id,不用varchar,索引设计,计算字段); 

    二。合理分表,使得单表数据规模适当; 

    三。用存储器分多个步骤处理。 

    四。数据预先处理。 

    五。分布在多台server上同时处理。 

    也就是分而治之与预处理。

    展开全文
  • 我在前年遇到过过亿条的数据。以至于一个处理过程要几个小时的。后面慢慢优化,查找一些经验文章。才学到了一些基本方法。综合叙之,与君探讨之。
  • java快速插入千万级数据,亲测91秒插入1700万数据!!!
  • java千万级别数据处理.doc
  • Python处理千万级数据

    千次阅读 2018-08-05 15:17:05
    从别人的论文里找到要用的数据的原始数据自己做过滤 捣鼓了两天觉得代码太慢开始用pandas做处理 不得不说最大的感触就是 pandas 以及numpy在一定程度上在还原MATLAB 比如MATLAB中利用逻辑值取数、元素的用法,...

    从别人的论文里找到要用的数据的原始数据自己做过滤

    捣鼓了两天觉得代码太慢开始用pandas做处理

    不得不说最大的感触就是 pandas 以及numpy在一定程度上在还原MATLAB

    比如MATLAB中利用逻辑值取数、元素的用法,pandas中有几乎一样的方法

    test:

    同时pandas中有很多很好用的方法,猜测使用了很多哈希值

    但是pandas同numpy一样,增量添加很慢

    也就是pandas适用于 已经确定size的数据的读取操作非常友好,但是把两个dataframe合并,是很慢的操作

    实际上先做了数据的拷贝再进行的拼接,可想而知是多慢了

    而Python里的list是一个动态数组,比较适合用于动态增长的情况,比如append,+,extends这样的方法

    总之记住只对dataframe进行读取就够啦

     

    最后写代码的时候 对于for循环要小心!!!

    想清楚这个代码是不是在循环里面还是外面!!

    把要在循环外面的代码先写着!!

    比如这次把生成dataframe的两行代码写了for循环里面

    查了好几遍才发现!! 真的很费时间!!

     

    时间的宝贵使人进步。

    加油。

     

    展开全文
  • 千万级数据处理解决方案(收集)

    千次阅读 2012-12-04 14:34:15
    http://blog.csdn.net/huang7914/article/details/2316160   http://www.cnblogs.com/ghd258/articles/260748.html
  • 千万级数据查询处理方案

    千次阅读 2019-01-31 11:29:21
    因为单表数据量已经达到了千万级,再多表关联已经达到亿级数据了。之前没有接触过这么大数据量的处理,所以刚接到这个项目时有点脑瓜子疼。 最开始我还是想通过优化sql与索引方式来提高查询的性能,但是效果并不...
  • 真实的数据,我的劳动成果!千万级数据Sql Server 与Mysql分析
  • 处理百万以上的数据提高查询速度的方法
  • 现需要开发一套程序用来快速迁移数据库,要求如下: 1.使用人员可以指定迁移数据库类型 如:(orcal,sqlServer,csv 迁移至mysql) 2.在迁移数据库时,可以只迁移指定字段. ...4.保护数据完整性,设计失败处理
  • 我也⼀一时兴起,想拿Python试试⼑刀,看看Python对于海量数据处理能⼒力如何。⽆无奈在百度和Google输⼊入“Python 海量数据”都⽆无果。可能是国内使⽤用python的不多, ⽤用python处理海量数据的就更少了。不过...
  • JAVA处理千万级数据(单线程)

    万次阅读 2017-12-21 18:00:01
    记录使用JAVA程序处理千万级的数据表 要求:原表有4000w+数据,需要对其中message字段进行数据处理,并将处理的结果写入result字段
  • 利用QT和C++实现数据的动态展示,数据量可达千万级别,仿真动态数据的实时生成和可视化
  • Mysql千万级别数据优化方案
  • 01背景 闲鱼目前实际生产部署环境越来越...当服务出现问题的时候,能否及时在海量的数据中定位到问题根因,成为考验闲鱼服务能力的一个严峻挑战。 线上出现问题时常常需要十多分钟,甚至更长时间才能找到问题原因,...
  • 微服务实战:百万千万级数据的实时处理架构(一)
  • 如何处理千万级以上的数据

    千次阅读 2015-12-16 19:12:22
    数据处理是一个头疼的问题,特别当达不到专业DBA的技术水准时,对一些数据库方面的问题感到无赖。所以还是有必要了解一些数据库方面的技巧,当然,每个人都有自己的数据库方面的技巧,只是八仙过海,所用的武功...
  • 记录使用JAVA程序处理千万级的数据表 要求:原表有4000w+数据,需要对其中message字段进行数据处理,并将处理的结果写入result字段中 优化:分表,sql的优化 过程: 最开始是啥都不懂,打算一次性将4000w条数据获取...
  • 主要用于可视化创建数据迁移用到的ktr转换脚本、kjb作业脚本,以及脚本需要配置的DB2信息、读写性能优化信息等,也可直接在客户端完成不同数据库之间的数据迁移。 1.1 安装 1.2 使用 2.1 ktr转换脚本 DB连接 2.2 kjb...
  • MySQL千万级数据量优化方案

    千次阅读 2020-02-19 21:52:30
    前言 ...千万级大表如何优化,这是一个很有技术含量的问题,通常我们的直觉思维都会跳转到拆分或者数据分区。除此之外,还有其他的思路和解决方案。根据本人多年的工作经验,做了如下总结。 方案 ...
  • 使用纯jdbc插入 这样会很快 可以使用批次来插入 但是会比springbuffer慢一些测试结果大概就是 使用MySQL数据库 91秒插入了 1700万数据
  • 主要给大家介绍了关于利用python如何处理百万条数据的相关资料,本文的教程非常适用于java新手,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧
  • 千万级数据导出Excel

    千次阅读 2020-05-15 16:18:55
    java实现海量数据导出到excel表格 翻了好久都没找到easyExcel动态创建sheet,只能自己封装一个。 要知道以 .xlsx结尾的excel文件每个sheet 只能写104万左右的数据量,想要写入500W条数据到excel,要么分到多个...
  • 阿里会在双 11 的当天竖起一面大的电子屏幕,实时展示淘宝这一天的成绩。例如成交额、访问人数、订单量、下单量、成交量等等。这个电子大屏的背后,就是用到我们所说的数据的实时处理技术。当然实...
  • ![图片说明](https://img-ask.csdn.net/upload/201803/02/1519966936_581903.png)![![图片说明](https://img-ask.csdn.net/upload/201803/02/1519966424_539301.png)图片说明]...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 88,998
精华内容 35,599
关键字:

千万级的数据怎么处理