热门标签 | HotTags
当前位置:  开发笔记 > 数据库 > 正文

如何处理大量数据

如何处理大量数据提高超大量数据数据库处理速度的方法-表分区庞大的数据量不光是查询操作,删除起来也痛苦.使用表分区的效果比较明显.特别是删除操作比较方便,速度也快.直接truncate掉按照rule分区以后的分区表数据,索引什么都会快速删除掉.至于查询速度

如何处理大量数据 提高超大量数据数据库处理速度的方法-表分区 庞大的数据量不光是查询操作,删除起来也痛苦. 使用表分区的效果比较明显.特别是删除操作比较方便,速度也快.直接truncate掉按照rule分区以后的 分区表数据,索引什么都会快速删除掉. 至于查询速度

如何处理大量数据

提高超大量数据数据库处理速度的方法-表分区

庞大的数据量不光是查询操作,删除起来也痛苦.

使用表分区的效果比较明显.特别是删除操作比较方便,速度也快.直接truncate掉按照rule分区以后的

分区表数据,索引什么都会快速删除掉.

至于查询速度的问题,索引比必不可少的(,如何建立高效的索引这篇文章就不再说明了.)

还有就是负载均衡. 数据库postgresql + postgresforest 可以达到很好的效果.(其实中心思想也是表分区.)

PostgreSQL 支持基本的表分区功能。 本节描述为何需要表分区以及你如何在你的数据库设计里面实现表分区。

概述

分区的意思是把逻辑上的一个大表分割成物理上的几块儿。 分区可以提供若干好处:

某些类型的查询性能可以得到极大提升。

更新的性能也可以得到提升,因为表的每块的索引要比在整个数据集上的索引要小。 如果索引不能全部放在内存里,那么在索引上的读和写都会产生更多的磁盘访问。

批量删除可以用简单地删除某个分区来实现 - 只要需求已经在分区设计是进行了规划。 DROP TABLE 比批量 DELETE 要快很多, 因为不需要有 VACUUM 的开销。

很少用的数据可以移动到便宜的、慢一些地存储介质上。

这种好处通常只有在表可能会变得非常大的情况下才有价值。 表在多大的情况下会从分区中收益取决于应用,不过有个基本的拇指规则就是表的大小超过了数据库服务器的物理内存大小。

目前,PostgreSQL 支持通过表继承进行分区。 每个分区必须做为单独一个父表的子表进行创建。父表自身通常是空的; 它的存在只是为了代表整个数据集。你在试图实现分区之前,应该先熟悉继承(参阅 Section 5.8)。

PostgreSQL 里面可以实现下面形式的分区:

范围分区

表被一个或者多个键字字段分区成"范围", 在这些范围之间没有重叠的数值分布到不同的分区里。 比如,我们可以为特定的商业对象根据数据范围分区,或者根据标识符范围分区。

列表分区

表是通过明确地列出每个分区里应该出现那些键字值实现的。

目前还不支持散列分区。

实现分区

要设置一个分区的表,做下面的步骤:

创建"主表",所有分区都从它上面继承下去。

这个表将没有什么数据,不要在这个表上定义任何检查约束, 除非你希望约束同样也适用于所有分区。同时在其上定义任何索引或者唯一约束也没有意义。

创建几个"子"表,每个都从主表上继承。 通常,这些表将不会对从主表继承过来集合增加任何字段。

我们将把子表称作分区,尽管它们就是普通的 PostgreSQL 表。

给分区表增加约束,定义每个分区允许的健值。

典型的例子是:

CHECK ( x = 1 )

CHECK ( county IN ( 'Oxfordshire', 'Buckinghamshire', 'Warwickshire' ))

CHECK ( outletID >= 100 AND outletID <200 )

确信这些约束保证在不同的分区里不会有重叠的键字。一个常见的错误是设置下面这样的范围:

CHECK ( outletID BETWEEN 100 AND 200 )

CHECK ( outletID BETWEEN 200 AND 300 )

这样做是错误的,因为它没说清楚健值 200 属于那个范围。

请注意在范围和列表分区的语法方面没有什么区别;这些术语只是用于描述的。

对于每个分区,在键字字段上创建一个索引,以及其它你想创建的索引。 (键字索引并非严格要求的,但是在大多数情况下它是很有帮助的。 如果你希望键字值是唯一的,那么你应该总是给每个分区创建一个唯一或者主键约束。

另外,定义一个规则或者触发器,把对主表的修改重定向到合适的分区表。

确保 postgresql.conf 里的配置参数 constraint_exclusion 是打开的。 没有这个参数,查询不会按照需要进行优化。

比如,假设我们为一个巨大的冰激凌公司构造数据库。 该公司每天都测量最高温度,以及每个地区的冰激凌销售。 概念上,我们需要一个这样的表:

CREATE TABLE measurement (

city_id int not null,

logdate date not null,

peaktemp int,

unitsales int

);

我们知道大多数查询都只会访问最后一周,最后一个月或者最后一个季度的数据, 因为这个表的主要用途是为管理准备在线报告。 为了减少需要存储的旧数据,我们决定值保留最近三年的有用数据。 在每个月的开头,我们都会删除最旧的一个月的数据。

在这种情况下,我们可以使用分区来帮助我们实现所有我们对表的不同需求。 下面的步骤描述了上面的需求,分区可以这样设置:

主表是 measurement 表,就像上面那样声明。

然后我们为每个月创建一个分区:

CREATE TABLE measurement_yy04mm02 ( ) INHERITS (measurement);

CREATE TABLE measurement_yy04mm03 ( ) INHERITS (measurement);

...

CREATE TABLE measurement_yy05mm11 ( ) INHERITS (measurement);

CREATE TABLE measurement_yy05mm12 ( ) INHERITS (measurement);

CREATE TABLE measurement_yy06mm01 ( ) INHERITS (measurement);

每个分区都是拥有自己内容的完整的表,只是它们从 measurement 表继承定义。

这样就解决了我们的一个问题:删除旧数据。 每个月,我们需要做的只是在最旧的子表上执行一个 DROP TABLE, 然后为新月份创建一个新的子表。

我们必须增加非重叠的表约束,所以我们的建表脚本就变成:

CREATE TABLE measurement_yy04mm02 (

CHECK ( logdate >= DATE &#39;2004-02-01&#39; AND logdate

) INHERITS (measurement);

CREATE TABLE measurement_yy04mm03 (

CHECK ( logdate >= DATE &#39;2004-03-01&#39; AND logdate

) INHERITS (measurement);

...

CREATE TABLE measurement_yy05mm11 (

CHECK ( logdate >= DATE &#39;2005-11-01&#39; AND logdate

) INHERITS (measurement);

CREATE TABLE measurement_yy05mm12 (

CHECK ( logdate >= DATE &#39;2005-12-01&#39; AND logdate

) INHERITS (measurement);

CREATE TABLE measurement_yy06mm01 (

CHECK ( logdate >= DATE &#39;2006-01-01&#39; AND logdate

) INHERITS (measurement);

我们可能还需要在键字字段上有索引:

CREATE INDEX measurement_yy04mm02_logdate ON measurement_yy04mm02 (logdate);

CREATE INDEX measurement_yy04mm03_logdate ON measurement_yy04mm03 (logdate);

...

CREATE INDEX measurement_yy05mm11_logdate ON measurement_yy05mm11 (logdate);

CREATE INDEX measurement_yy05mm12_logdate ON measurement_yy05mm12 (logdate);

CREATE INDEX measurement_yy06mm01_logdate ON measurement_yy06mm01 (logdate);

我们选择先不建立更多的索引。

如果数据只进入最新的分区,我们可以设置一个非常简单的规则来插入数据。 我们必须每个月都重新定义这个规则,这样它总是指向当前分区。

CREATE OR REPLACE RULE measurement_current_partition AS

ON INSERT TO measurement

DO INSTEAD

INSERT INTO measurement_yy06mm01 VALUES ( NEW.city_id,

NEW.logdate,

NEW.peaktemp,

NEW.unitsales );

我们可能想插入数据并且想让服务器自动定位应该向哪个分区插入数据。 我们可以用像下面这样的更复杂的规则集来实现这个目标。

CREATE RULE measurement_insert_yy04mm02 AS

ON INSERT TO measurement WHERE

( logdate >= DATE &#39;2004-02-01&#39; AND logdate

DO INSTEAD

INSERT INTO measurement_yy04mm02 VALUES ( NEW.city_id,

NEW.logdate,

NEW.peaktemp,

NEW.unitsales );

...

CREATE RULE measurement_insert_yy05mm12 AS

ON INSERT TO measurement WHERE

( logdate >= DATE &#39;2005-12-01&#39; AND logdate

DO INSTEAD

INSERT INTO measurement_yy05mm12 VALUES ( NEW.city_id,

NEW.logdate,

NEW.peaktemp,

NEW.unitsales );

CREATE RULE measurement_insert_yy06mm01 AS

ON INSERT TO measurement WHERE

( logdate >= DATE &#39;2006-01-01&#39; AND logdate

DO INSTEAD

INSERT INTO measurement_yy06mm01 VALUES ( NEW.city_id,

NEW.logdate,

NEW.peaktemp,

NEW.unitsales );

请注意每个规则里面的 WHERE 子句正好匹配其分区的 CHECK 约束。

我们可以看出来,一个复杂的分区方案可能要求相当不少的 DDL。 在上面的例子里我们需要每个月创建一次新分区,因此写一个脚本自动生成需要的 DDL 是明智的。

还要注意下面的事项:

目前还没有什么办法校验所有 CHECK 是相互排他的。 数据库设计者必须注意这一点。

目前还没有简单的办法声明数据行绝对不能插入主表。 主表上的一个 CHECK (false) 约束将被所有子表继承, 因此不能这么用。一个可行的办法是在主表上设置一个 ON INSERT 触发器,总是抛出错误。(另外,这样的触发器也可以用于重定向数据到合适的子表, 而不是用上面建议的那样一套规则。)

分区也可以使用一个 UNION ALL 试图来安排:

CREATE VIEW measurement AS

SELECT * FROM measurement_yy04mm02

UNION ALL SELECT * FROM measurement_yy04mm03

...

UNION ALL SELECT * FROM measurement_yy05mm11

UNION ALL SELECT * FROM measurement_yy05mm12

分区和约束排除

约束排除(Constraint exclusion)是一种查询优化技巧, 它改进了用上面方法定义的表分区的性能。比如:

SET constraint_exclusion = on; SELECT count(*) FROM measurement WHERE logdate >= DATE &#39;2006-01-01&#39;;

如果没有约束排除,上面的查询会扫描 measurement 表中的每一个分区。 打开了约束排除之后,规划器将检查每个分区的约束然后试图证明该分区不需要被扫描, 因为它不能包含任何符合 WHERE 子句条件的数据行。 如果规划器可以证明这个,它就把该分区从查询规划里排除出去。

你可以使用 EXPLAIN 命令显示一个规划在 constraint_exclusion 打开和关闭情况下的不同。用上面方法设置的表的典型的缺省规划是:

SET constraint_exclusion = off; EXPLAIN SELECT count(*) FROM measurement WHERE logdate >= DATE &#39;2006-01-01&#39;; QUERY PLAN ----------------------------------------------------------------------------------------------- Aggregate (cost=158.66..158.68 rows=1 width=0) -> Append (cost=0.00..151.88 rows=2715 width=0) -> Seq Scan on measurement (cost=0.00..30.38 rows=543 width=0) Filter: (logdate >= &#39;2006-01-01&#39;::date) -> Seq Scan on measurement_yy04mm02 measurement (cost=0.00..30.38 rows=543 width=0) Filter: (logdate >= &#39;2006-01-01&#39;::date) -> Seq Scan on measurement_yy04mm03 measurement (cost=0.00..30.38 rows=543 width=0) Filter: (logdate >= &#39;2006-01-01&#39;::date) ... -> Seq Scan on measurement_yy05mm12 measurement (cost=0.00..30.38 rows=543 width=0) Filter: (logdate >= &#39;2006-01-01&#39;::date) -> Seq Scan on measurement_yy06mm01 measurement (cost=0.00..30.38 rows=543 width=0) Filter: (logdate >= &#39;2006-01-01&#39;::date)

部分或者全部分区可能会使用索引扫描而不是全表扫描, 不过这里要表达的意思是我们没有必要扫描旧的分区旧可以回答这个查询。 在我们打开约束排除之后,我们可以得到生成同样回答的明显节省的规划:

SET constraint_exclusion = on; EXPLAIN SELECT count(*) FROM measurement WHERE logdate >= DATE &#39;2006-01-01&#39;; QUERY PLAN ----------------------------------------------------------------------------------------------- Aggregate (cost=63.47..63.48 rows=1 width=0) -> Append (cost=0.00..60.75 rows=1086 width=0) -> Seq Scan on measurement (cost=0.00..30.38 rows=543 width=0) Filter: (logdate >= &#39;2006-01-01&#39;::date) -> Seq Scan on measurement_yy06mm01 measurement (cost=0.00..30.38 rows=543 width=0) Filter: (logdate >= &#39;2006-01-01&#39;::date)

请注意,约束排除只由 CHECK 约束驱动,而不会由索引驱动。 因此,在键字字段上定义索引是没有必要的。 在给出的分区上是否需要建立索引取决于那些扫描该分区的查询通常是扫描该分区的一大部分还是只是一小部分。 对于后者,索引通常都有帮助,对于前者则没有什么好处。

还有下面的注意:

约束排除只是在查询的 WHERE 子句包含约束的时候才生效。 一个参数化的查询不会被优化,因为在运行时规划器不知道改参数会选择哪个分区。 由于某些原因,像 CURRENT_DATE 这样的"稳定的(stable)"函数必须避免。 把分区键字和另外一个表的字段连接起来也不会得到优化。

在 CHECK 约束里面避免跨数据类型的比较, 因为目前规划器会无法证明这样的条件为假。比如,下面的约束会在 x 是整数字段的时候可用,但是在 x 是一个 bigint 的时候不能用:

CHECK ( x = 1 )

对于 bigint 字段,我们必须使用类似下面这样的约束:

CHECK ( x = 1::bigint )

这个问题并不仅仅局限于 bigint 数据类型 — 它可能会发生在任何约束的缺省数据类型与其比较的字段的数据类型不匹配的场合。 在提交的查询里的跨数据类型的比较通常是 OK 的,只是不能在 CHECK 条件里。

目前,在主表上的 UPDATE 和 DELETE 命令并不执行约束排除。

主表的所有分区上面的所有约束都认为是约束排除了的,因此,大量的分区会显著增加查询规划的时间。

别忘记你仍然需要为每个分区独立运行 ANALYZE。 类似下面的命令

ANALYZE measurement;

是只会处理主表的。

UNION ALL SELECT * FROM measurement_yy06mm01;

不过,约束排除目前还不支持用这种方式定义的分区。 还有,重建试图也给增加和删除数据集里面的独立分区增加了额外的步骤。


推荐阅读
  • 本文详细介绍了Java代码分层的基本概念和常见分层模式,特别是MVC模式。同时探讨了不同项目需求下的分层策略,帮助读者更好地理解和应用Java分层思想。 ... [详细]
  • RocketMQ在秒杀时的应用
    目录一、RocketMQ是什么二、broker和nameserver2.1Broker2.2NameServer三、MQ在秒杀场景下的应用3.1利用MQ进行异步操作3. ... [详细]
  • 包含phppdoerrorcode的词条 ... [详细]
  • 在将Web服务器和MySQL服务器分离的情况下,是否需要在Web服务器上安装MySQL?如果安装了MySQL,如何解决PHP连接MySQL服务器时出现的连接失败问题? ... [详细]
  • 操作系统如何通过进程控制块管理进程
    本文详细介绍了操作系统如何通过进程控制块(PCB)来管理和控制进程。PCB是操作系统感知进程存在的重要数据结构,包含了进程的标识符、状态、资源清单等关键信息。 ... [详细]
  • 基于iSCSI的SQL Server 2012群集测试(一)SQL群集安装
    一、测试需求介绍与准备公司计划服务器迁移过程计划同时上线SQLServer2012,引入SQLServer2012群集提高高可用性,需要对SQLServ ... [详细]
  • ZooKeeper 入门指南
    本文将详细介绍ZooKeeper的工作机制、特点、数据结构以及常见的应用场景,包括统一命名服务、统一配置管理、统一集群管理、服务器动态上下线和软负载均衡。 ... [详细]
  • Linux CentOS 7 安装PostgreSQL 9.5.17 (源码编译)
    近日需要将PostgreSQL数据库从Windows中迁移到Linux中,LinuxCentOS7安装PostgreSQL9.5.17安装过程特此记录。安装环境&#x ... [详细]
  • 本文介绍如何在将数据库从服务器复制到本地时,处理因外键约束导致的数据插入失败问题。 ... [详细]
  • 在JavaWeb项目架构中,NFS(网络文件系统)的实现与优化是关键环节。NFS允许不同主机系统通过局域网共享文件和目录,提高资源利用率和数据访问效率。本文详细探讨了NFS在JavaWeb项目中的应用,包括配置、性能优化及常见问题的解决方案,旨在为开发者提供实用的技术参考。 ... [详细]
  • (1)前期知识:1. 单机架构:单一服务器计算机——其处理能力和存储容量有限。2. 集群架构(负载均衡器与多节点服务器)——通过增加节点数量来提升系统性能和可靠性,实现高效的任务分配和资源利用。 ... [详细]
  • 第二章:Kafka基础入门与核心概念解析
    本章节主要介绍了Kafka的基本概念及其核心特性。Kafka是一种分布式消息发布和订阅系统,以其卓越的性能和高吞吐量而著称。最初,Kafka被设计用于LinkedIn的活动流和运营数据处理,旨在高效地管理和传输大规模的数据流。这些数据主要包括用户活动记录、系统日志和其他实时信息。通过深入解析Kafka的设计原理和应用场景,读者将能够更好地理解其在现代大数据架构中的重要地位。 ... [详细]
  • 2016-2017学年《网络安全实战》第三次作业
    2016-2017学年《网络安全实战》第三次作业总结了教材中关于网络信息收集技术的内容。本章主要探讨了网络踩点、网络扫描和网络查点三个关键步骤。其中,网络踩点旨在通过公开渠道收集目标信息,为后续的安全测试奠定基础,而不涉及实际的入侵行为。 ... [详细]
  • Nginx不仅是一款轻量级的高性能Web服务器,还具备出色的负载均衡和反向代理功能。它支持复杂的正则匹配规则、动静内容分离以及灵活的URL重写功能,使得配置和管理更加便捷高效。此外,Nginx提供了多种负载均衡算法,如轮询、加权轮询、最少连接数等,以满足不同应用场景的需求。 ... [详细]
  • IIS 7及7.5版本中应用程序池的最佳配置策略与实践
    在IIS 7及7.5版本中,优化应用程序池的配置是提升Web站点性能的关键步骤。具体操作包括:首先定位到目标Web站点的应用程序池,然后通过“应用程序池”菜单找到对应的池,右键选择“高级设置”。在一般优化方案中,建议调整以下几个关键参数:1. **基本设置**: - **队列长度**:默认值为1000,可根据实际需求调整队列长度,以提高处理请求的能力。此外,还可以进一步优化其他参数,如处理器使用限制、回收策略等,以确保应用程序池的高效运行。这些优化措施有助于提升系统的稳定性和响应速度。 ... [详细]
author-avatar
空空空空轨
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有