|
第5章 部署问题
本章由李博@xjtu(role0523 at gmail dot com)翻译,转载请注明作者 敬请关注hsqldb.blogchina.com和www.sawpad.com的翻译工作 5.1 本章目的
许多在论坛或邮件组中重复出现的问题将会在本文档中进行解答。如果你打算在应用程序中使用HSQLDB的话,那么你应该好好阅读一下本文章。本章的内容覆盖与系统相关的问题。与SQL相关的问题请参看“SQL问题”一章。 5.2 操作模式和表
HSQLDB有许多操作模式和特性,这可以允许它可以使用在各种不同的情况下。不通应用程序的内存使用率、速度和访问能力都受到HSQLDB部署的影响。 5.2.1 操作模式
是以独立服务器进程(separate server process)还是以进程内数据库(in-process database)模式运行HSQLDB,都应该基于下面的3点:
* 当HSQLDB在一台单独的机器上以服务器模式运行时,它是不受应用程序运行的主机的硬件故障的影响的。 * 当HSQLDB在和应用程序相同的机器上以服务器模式运行时,它是不受应用程序崩溃和内存泄漏的影响。 * 由于传输每个JDBC访问的数据流带来的开销,使得Server模式连接比in-process模式的连接要慢。
5.2.2 表
TEXT表是为其数据是可交换格式(例如,CSV)的应用程序设计的。TEXT表不适合数据的常规存储。
MEMORY表和CACHED表通常用于数据存储。这两中表有以下的区别:
* 当数据库启动时,所有MEMORY表的数据从.script文件中读出来,存储在内存中。相比而言,CACHED表中的数据在访问该表是才会读到内存中,此外每个CACHED表只有部分数据保留在内存中,允许表中存储比保留在内存的数据中更多的数据。 * 当数据库正常关闭时,MEMORY表中的所有数据将会写到磁盘上。相比而言,发生改变的CACHED表中的数据才会写道磁盘上,还有就是所有CACHED表中的数据将会压缩备份。 * 所有CACHED表中数据缓存的大小和容量都是可以配置的。这使得CACHED表中的所有还从那到内存中还是有可能的。这种情况,访问速度还可以,但和MEMORY表相比稍稍慢了一点。 * 对于通常的应用,少量数据推荐使用MEMORY表,大量数据集合推荐使用CACHED表。对于速度要求较高并且有较大的内存空间的特殊应用,MEMORY表也是可以适用于大量数据的。
5.2.3 大对象
JDBC Clobs 由LONGVARCHAR类型的列支持,JDBC Blobs由LONGVARBINARY类型的列支持。当大对象(LONGVARCHAR, LONGVARBINARY, OBJECT)存储在包含普通字段的表中时,最好用两个表来存储。第一个表包含普通的字段,第二个表包含大对象和标识字段。使用这种方法有两个好处。(a)第一个表通常是以MEMORY表形式创建的,只有第二个表是一个CACHED表;(b)大对象在查询过程中可以根据它们的表示单独获取,而不用加载到内存中来查找行记录。下面是两个表和一个select查询的例子,它将两种类型的表分离开:
CREATE MEMORY TABLE MAINTABLE(MAINID INTEGER, ......);
CREATE CACHED TABLE LOBTABLE(LOBID INTEGER, LOBDATA LONGVARBINARY);
SELECT * FROM (SELECT * FROM MAINTABLE WHERE ) JOIN LOBTABLE ON MAINID=LOBID;
括号内select查询查找符合条件,但与LOBTABLE无关的记录,当找到这些记录时,才从LOBTABLE中获取大对象数据。 5.2.4 部署的环境
用于存储HSQLDB数据库的文件都位于相同的目录下。新的文件总是被数据库引擎创建,而后又删除。应该知道下面两个基本的原则:
* 在数据库文件存储的文件夹中,运行HSQLDB的Java进程必须具有所有的权限。其中包括创建和删除的权限。 * 文件系统必须具有足够的空余空间,用于生成永久性文件和临时文件。.log文件默认的最大体积为200M。.data文件的体积可以增至8GB。.backup文件的体积可以达到.data文件的50%。在SHUTDOWN COMPACT(关闭数据库的一种方式)时生成的临时文件在体积上与.data文件相同。
5.3 内存和磁盘使用
程序的内存使用可以看作有两个不同部分:数据库表数据的内存使用,建立结果集和其它内部操作的内存使用。此外,当使用事务处理时,内存用来用来保存回滚需要的信息。
自从版本1.7.1以来,内存使用和前几个版本比较而言,已经减小了很多。一个MEMORY表的内存使用是所每一行数据据库录的内存使用之和。每一个MEMORY表行记录是一个具有2个int或引用变量的Java对象,它包含了一个该行记录中字段所表示的对象数组。每一个字段都是一个如Integer,Long,String等的对象。此外,表中每个索引都给改行记录加上一个节点对象。每个节点对象有6个整形或引用变量。所以,只有一个INTEGER列的数据库表的每行记录将会有4个对象,总共有10个变量,其中每个变量4个字节??通常每个行记录要占据80个字节。在这之外,数据库中每个额外的列添加至少几个字节到每个行记录的大小上。
一个结果集行记录的内存使用有更少的开销(更少的变量且没有所以节点),但仍然使用了很多内存。结果集中所有的行记录都是在内存中建立的,所以数据量很大的结果集是不可能的。在server模式的数据库中,一旦数据库server返回了结果集,结果集内存将会从server中释放出来。在进程内数据库中,当应用程序释放java.sql.ResultSet对象时,数据库就会释放内存。Server模式需要额外的内存来返回结果集,因为它们将所有的结果集转化到一个字节序列中,然后传送到客户端。
当在CACHED表中执行UPDATE和DELETE语句时,所有有变化的行记录集,包括因为执行UPDATE操作改变的数据,将会在操作过程中驻留在内存中。这意味着对涉及大量数据的CACHED表行记录集,不可能执行delete或者update操作。对于较小的结果集是可以使用这些操作的。
当使用SET AUTOCOMMIT OFF开启事务支持时,所有insert,delete或update操作列表存储在内存中,因此,当进行ROLLBACK事务时,这些操作能够被撤销。跨越几百个数据改变的事务将会花费很多的内存知道下一个COMMIT或ROLLBACK清除了操作列表。
大多数JVM执行时的内存分配会一直到最大值(通常默认为64MB),当大量内存表被使用时,或当CACHED表中行记录的平均大小大于几百个字节时,这个内存大小通常是不够的。内存分配的最大值可以在用来运行HSQLDB的命令行中进行设置。例如,用版本1.3.0的Sun JVM加上-Xmx参数可以将最大值增加到256MB。
1.8.0的HSQLDB为存储在数据中的Integer或String等这些不可编对象使用了快速缓存。在大多数情况下,因为只有最经常使用的对象作为少量备份保存在内存中,所以这将会更进一步减少内存使用,。 5.3.1 缓冲内存分配
在CACHED表中,数据时存储在磁盘上的,只有行等于最大数量的行记录一直驻留在内存中。默认的值等于3*16384行。可以设置hsqldb.cache_scale的数据库属性来改变这个大小。因为任意CACHED表中的任意随机行记录的子集可以被保留在内存中,所以chached行记录需要的内存大小可以达到包含最大字段数据的行的数量。例如,如果有一个100,000行的表包含40,000行,每行有1000个字节数据的行记录和60,000行每行100个自己的行记录,那么表的缓存可以增至包含几乎50000个行记录,包含了所有40000个较大的行记录。
还有一个数据库的属性hsqldb.cache_size_scale和hsqldb.cache_scale属性联合起来使用。这个属性给缓存的行记录总的大小加上了一个限制。当两个属性的默认值都使用了时,行记录其总大小的限制大约时50MB。(这是行记录和索引的二进制映像的大小,因为数据用Java objects来表示,所以它能被装化成实际内存的2到4倍还要多)
If如果内存有限制的话,hsqldb.cache_scale 或 hsqldb.cache_size_scale属性的值可以减少一些。在上面的例子中,如果hsqldb.cache_size_scale的值从10降低到8,那么总的二进制的极限将会从50MB降低到12.5MB。这将会允许缓存行记录的数量达到50000个小的行记录,但只能有12500个稍大的行记录。 5.4 管理数据库连接
在所有的运行模式中(不管是Server模式还是in-process模式)数据库引擎都支持多重连接。进程内(独立)模式支持来自同一个Java虚拟机内部的客户端连接,而服务器模式支持通过网络来自不同的客户端连接。
连接池软件可以用来连接数据库,但这不是必须的。在其它的数据库引擎中,使用连接池的原因不适用于HSQLDB
* 允许在一个很耗时的查询在后台执行的时候,执行一个新的查询。这在1.8.0版本的HSQLDB中被阻塞了,当它执行一个查询,只有完成后,才会处理下一个查询。这个功能正在开发中,将会在将来的版本中引进来。 * 考虑性能原因,限制数据库的最大并发连接数。在HSQLDB中,这个仅当你的应用程序设计成为每一个小任务打开和关闭连接的方式时,才比较有用。 * 在一个多线程应用中控制事务处理。这个在HSQLDB中也是比较有用的。例如,在一个web应用中,一个事务可能唤醒一些处于查询或者跨越网页的用户行为之间的一些进程。一个单独的连接应该用于每个HTTP session,所以当完成事务或回滚式,工作可以被提交。虽然这种用法不能被用在大多数的其他数据库引擎上,但是HSQLDB式完全可以处理超过100个并发的HTTP session作为一个单独的JDBC连接。
像记录用户登陆和注销行为这样的不会同时式多线程和事务性的应用,不需要多于一个的连接。一个连接可以不确定的保持连接,仅当因为网络问题关闭时回重新打开。
当使用1.7.2版本之前的HSQLDB的进程内数据库时,应用程序必须至少保持一个数据库连接打开,否则,数据将会关闭,进一步尝试创建连接可能失败。1.7.2版本以后,这个不再是必须的了,数据库不会自动关闭一个通过建立连接保持打开状态的进程内数据库。关闭数据库时可以使用一个显式的SHUTDOWN命令,带或不带参数都可以。在1.8.0版本中,一个连接属性可用来恢复原来的行为。
当使用一个server数据库时(可以延伸为使用一个进程内数据库),必须特别小心避免频繁的创建和关闭JDBC。当数据库负荷比较大时,频繁的连接和关闭数据库回导致不成功的连接尝试。 5.5 升级数据库
任何1.8.0以前的HSQLDB的发布版本都必须升级到最新的1.8.0版,包括使用1.8.0的RC版本创建的数据库。“使用脚本命令升级”一小节下面的说明适用于任何情况。
一旦数据库升级到1.8.0,使用Hypersonic或以前版本的HSQLDB将不再被使用。
在涉及修改以下.script文件的升级过程中可能存在这一些潜在的规则问题:
* 版本1.8.0不支持重复的索引名称,这在1.7.2版本之前是允许的。 * 版本1.8.0不支持表中重复的列名称,这在1.7.0之前是允许的 * 版本1.8.0不能像1.7.2版本之前,对于外键不能创建相同的索引 * 版本1.8.0不支持没有双引号的SQL标识符的表或列名称.
5.5.1使用脚本命令升级
从1.7.2或1.7.3升级到1.8.0,主需要简单地在旧版本上执行SET SCRIPTFORMAT TEXT和SHUTDOWN SCRIPT命令,然后用新版本的引擎打开。这时升级就完成了。
从更老版本(1.7.1之前)升级不包括CACHED表的数据库文件时,简单地SHUTDOWN9(关闭)旧版本,打开新版本即可。如果.script文件中出现什么问题地话,编辑.script文件之后再试一次。
从更老版本(1.7.1之前的版本)的包含CACHED表的数据库文件中升级的时候,使用下面的SCRIPT步骤。在所有版本的HSQLDB和1.4.3的Hypersonic中,使用”SCRIPT filename”命令(作为一个SQL查询使用)可以让你把数据库中的所有记录,包括数据库对象定义和数据,保存到你选择的文件中。你可以使用老版本的数据库引擎导出一个脚本文件,在1.8.0中作为数据库打开脚本。
Procedure 5.1. 使用脚本升级步骤
1. 在老版本的数据库管理器(DatabaseManager)中打开原始的数据库。 2. 执行SCRIPT命令,例如,SCRIPT 'newversion.script'用来创建一个包含了数据库拷贝的.script文件 3. 在newversion的例子中,在不同的文件夹下使用1.8.0版本的DatabaseManager来创建一个新的数据库。 4. SHUTDOWN数据库 5. 复制第二步中的newversion.script文件覆盖4中数据库产生同名文件 6. 试着用DatabaseManager打开新的数据库。 7. 如果数据中出现什么矛盾的话,就会在控制台中报告脚本的行数,同时打开进程也被中止了。再次尝试打开之前,编辑和校正newversion.script文件中的错误。使用下一小节中的指导内容(手动改动.script文件)。使用一个能够处理大文件的程序编辑器,同时对于文字中较长的行不要换行。
5.5.2 手动改动.script文件
在1.8.0中,所有的ALTER TABLE命令对于改变数据结构和它们的名字都是可行的。但是,如果,旧的数据库由于数据冲突或者索引或列名的使用和1.8.0不兼容而不能被打开的话,手动编辑SCRIPT文件是可行的办法。
只要它们不影响现存数据的完整性,下列改动是可以使用的:
* 表、列和索引的名称可以改变。 * CREATE UNIQUE INDEX ... 到 CREATE INDEX ... 反之亦然。
一个唯一的所以常常可以被转化成一个普通的索引,一个不唯一的所有只能够被转化成一个唯一的索引,前提是,每行记录中,列中的表数据是唯一的。
* NOT NULL
一个非空的约束常常可以去除,只有在列中的表数据没有null值的情况,才添加NOT NULL约束。
* PRIMARY KEY
可以去除或添加一个主键约束。但当该列有一个外键引用的话,该逐渐不能去除。
* COLUMN TYPES
列类型的一些变动是可以的。例如,一个INTEGER列可以改成BIGINT,或DATE,TIME以及TIMESTAMP列可以改成VARCHAR列。
完成改动之后,保存修改的*.script文件,然后你可以正常打开数据库了。 5.6 备份数据库
每一个数据库的数据由同一个文件夹中5个以上的文件组成。其后缀分别为*.properties, *.script, *.data, *.backup and *.log(以*.lck结尾的文件用来控制数据库的访问,所以不应该备份)。这些文件应该备份在一起。这些文件可以在数据库引擎运行的时候进行备份,但是,千万要小心,在备份过程中,不能发生CHECKPOINT或SHUTDOWN操作。在CHECKPOINT之后立即进行备份时非常有效的。*.data文件可以从备份文件中排除掉。在这种情况下,当恢复数据时,需要一个虚拟的*.data文件(它可以为空,0个字节)。如果数据备份被还原,数据库引擎将会扩展*.backup文件来替换这个虚拟的文件。如果*.data文件没有被备份,在还原之前,*.properties文件可能必须修改以保证它包含了modified=yes,而不是modified=no。如果数据库备份是在一个CHECKPOINT之后进行的话,那么*.log文件也可以被排除掉,这样就把重要的文件减少到*.properties, *.script 和 *.backup。可以使用例如把文件都压缩在一个归档文件中的正常的备份方法
|