CIO:为什么超级 [商业级 RDBMS] 系统后劲不足?我们不是刚刚升过级吗?
经理:是的,但是升级没有被接受。
CIO:没有被接受?听起来就像是医生移植器官一样。难道说 CPU 出现了排异反应?(笑)
经理:(冷静地)不,只是没有被用户接受。系统速度还是太慢了。
CIO:我们已经在">硬件设备上投入了 [X] 百万美元,它最好能达到目标,否则我恐怕只能将它拆成了零件,连同您的
首席架构师一起请出公司!
经理:我没法解释。白皮书里说„„(看着犹如天书一般难以理解的商业文章,无法理清头绪)
CIO:我也浏览了一遍那本手册。上周您手下的所有员工都穿着印有这家供应商徽标的 T 恤,我注意到他们现在又都换回了普通的马球衫。是不是发生了什么事情?
经理:我们无法达到预期的数字。我们正在调优。
CIO:调优?可是系统正在严重恶化。这可不是所谓的“调优”。
经理:(声音转小)是,我知道。(口中念念有词地缓缓走开)
把一切都归咎于经理是不公平的。把不适合具体工作的硬件强加给经理,不考虑硬件最初的设计目标与工作根本不符,却希望得到硬件无法实现的成果?
在数据库以外的地方,“批量数据处理”只有一个含义:提取、转换、加载 (ETL),而可供选择的工具有几十种。这些选择将会迅速升级,造成多米诺效应,不但要求必要的基础架构(如 ETL 机),还要求了解工具、了解如何应用工具的人员。可伸缩性不仅仅与硬件有关,还与后勤密切相关;目标是在不聘用大量开发人员来提供支持的前提下开发更多的功能。但如果不想聘用工具专家又会怎样?如果 UNIX 基础知识以及出色处理 SQL 和企业自有信息的能力是大规模成功数据处理环境的核心技能集,又会怎样?
数据库机内的批量数据处理只有一种形式:使用 SQL 的 insert/select 语句,通常在中间数据库表和/或持久数据库表(即 ELT)之间执行。除了 SQL 为支持这种形式而生成的机制之外(不需要为业务逻辑手动编写 SQL 语句!),我们还应该深入探索硬件方面,确定这种方法对于大规模数据是否可行。
通用平台是“水平的”,也就是说 CPU 与磁盘驱动器物理分离,通过基板连接,共享硬件级的一切资源。复制就是从磁盘获取大量数据,经过基板,通过 CPU 和具有表的逻辑表示形式的软件,最终传递到基板,再返回磁盘。在这样的数据流中,数据可以在(饱和的)基板上来回传递。这必然会造成庞大、臃肿、单体式的查询,因为我们只能在获得数据之后处理数据。可以说,这种多指令多数据 (MIMD) 模型无法为了实现批量处理而进行伸缩。
相比之下,IBM® Netezza® 平台是使用精心优化的商业级零件专门制作的专有组装平台,其中的 CPU 与一个磁盘驱动器配对(无共享硬件)。创建表时,从逻辑上来说,只存在一个表,但从物理上来说,这个表的各个部分可以分别处于各 CPU/磁盘组合当中,其中 10 个这种类型的 CPU/磁盘对可能会将一个包含 1,000 条记录的表分为 10 个位置存储,每个位置存储 100 条记录。但一次查询即可同时查询所有这些 CPU,也就是说,并行移动 10 个各包含 100 条记录的组,所需的时间是将全部 1,000 条记录作为单独一个数据块进行移动时的十分之一。这种模型称为单指令多数据 (SIMD) 模型。SIMD 能够为实现批量处理而进行大幅扩展,因此配备 90 枚或更多 CPU 的 TwinFin® 能够在极短的时间内处理数十亿条记录,远胜过能力相似的通用竞争产品。
许多决定将逻辑从 ETL 机转移到 Netezza 的企业都会受困于一个简单的问题:我们能否扩展这种方法?简而言之,SQL insert/select 语句有一些后勤工作,我们必须合理加以利用,以形成一种可靠的方法基础。请考虑以下查询:
Insert into EMPLOYEE (EMP_ID, EMP_FNAME, EMP_LNAME, EMP_START_DATE) select ID, FirstName, LastName, St_Date from OldEmployees;
看起来很简单,或许应该说有些过于简单。那么再请看下面这条查询:
Insert into EMPLOYEE select ID, FirstName, LastName, St_Date from OldEmployees;
请注意,在上面的查询中,insert 词组是隐式的。或许有些读者已经发现了这里存在的重大危险。如果后续我们在这些内容中间添加一个列,则会造成其他列发生偏移,使之无法与目标列正确对齐。有些用户表示,至少有一个目标列会出现问题,但事实是怎样的?我曾经遇到过未能对齐的查询仍然运行数天乃至数月之后才被发现的情况。这些查询只是碰巧与可接受的目标数据类型相符,但内容完全是错误的。我们必须掌控这样的问题。
如果是包含 150 列的事实表,情况会怎样?insert/select 子句会立即失去控制。如果我们需要添加或删除列,或者需要根据数据模型的更改来更新查询,情况又会怎样?这些情况会造成查询功能冻结,导致解决方案脆弱不堪。细微的变化可能就会导致整个解决方案工作失常。
我们可以采用的最好方法就是将目标列与源规则(将填充目标列的 SQL Select 词组的元素)保持一致:
EMP_ID ID
EMP_FNAME FirstName
EMP_LNAME LastName
EMP_START_DATE St_Date
我们可以对上面这样的模板加以扩展,限制数据库机。目标列始终与源保持一致/select 列永远不会发生偏移。这听起来是否就像是采用某种更为先进的方法,而非仅仅依靠 ETL 工具?不要被愚弄了。一切的目的就是简化和降低 SQL 语句生成后勤工作的复杂度。这种结构有助维护,而且无需艰难的影响审查。它能极为轻松地扫描简单的工具,并将其内容与目录内容进行对比,以查找、应用或直接报告更改。但请务必牢记,只要数据模型发生更改,其所有列都会受到影响。在这种情况下,我们主要关注的是异常,数据模型中 90% 以上的协调工作可能都自动完成。因此,新数据模型的协调工作会变得敏捷起来——或者可以说是极其敏捷。
拥有这种掌控查询生成的力量之后,我们就能自由处理大量查询,而不会失去对后勤的控制力。这种方法能否扩展?答案是肯定的,而且已经得到了实现。这种模板更高级的形式是框架引擎的推进动力,我们常常会看到数十个此类查询按照受控制的次序加以执行,致力于实现某种功能目标,这种方法简化了维护和重用。
MIMD 与 SIMD 之间在后勤方面的主要差异是:使用 MIMD 时,我们必须使用更少、更复杂的 SQL 语句,这些语句必然是串行化的,因为它们会使硬件饱和。SIMD 鼓励我们使用更多、更简单的 SQL 语句,同时并行运行这些语句,因为机器将迅速分派语句。因此 SIMD 查询能够以比同等的 MIMD 查询更快的速度完成。
通用 MIMD 平台从最初起便有着较高的(也是永久性的)复杂性,专门构建的 SIMD 平台则允许我们从简单的地方入手,并始终保持简单性。简单就意味着一切易于维护、扩展和排除故障,这奠定了贯穿系统整个使用寿命的敏捷性基础。