电脑技术学习

了解ASE中的外键验证技术

dn001

  已经写入的存储过程将对指定引用约束、外键表或整个数据库中的任意一个执行检查。这些检查将适当的在内部生成上述命令,并通过 execute immediate 来执行它们。(代码可在网站 www.sybase.com/developer/codexchange 的 ASE/ Management/Administration 部分中找到。)

  权限问题

  现在,我们来考虑一个比较深奥的问题。不管是否存在外键限制,表 FK 的所有者可能并不具备对表 PK 的选择权限。表 PK 的所有者只能向表 FK 的所有者提供对列 A 和 B 的引用权限。在这种情况下,表 FK 的所有者无法验证其数据,因为上述查询是动态生成的,在执行时需要有对 PK.A 和 PK.B 的选择权限。对于非系统管理员的用户,最好先检查一下是否具备对 FK 和 PK 列的选择权限。(在这里,笔者假设两个表处于同一数据库中。否则,仅用 SQL 来确定是否具备选择权限是不可行的。)如果提供了外键限制,则可以通过 sysreferences 表来确定主键表和列 ID (colid) 或列名称。随即,通过下列规则在 sysprotects 表中确定表或列的权限(例如,select):

  _ 如果用户拥有该表,那么其便拥有权限(除非他撤销了自己的隐式权限)。

  _ 此外,如果用户拥有对有效角色的授权行,那么其便拥有权限。

  _ 此外,如果用户拥有授权行,那么其便拥有权限。

  _ 此外,如果对用户所属的组拥有授权行,并且没有对其撤销行,那么该用户便拥有权限。

  使用字符串自变量/参数代替临时表

  上面已指出有三个(约束、表或数据库)存储过程,将存储过程(比方说,sp_object_access)进行编码以便仅检查对 FK 或 PK 列的权限时,应很好地遵循模块化规定。这使我们可以将 colid(列名称)列表作为单列临时表传递。从 SQL-BackTrack 逻辑转储/负载来看,正如我们很多人都知道,这会引出其他麻烦。逻辑转储/负载无法重新创建存储过程子例程,该子例程是由其他存储过程创建的临时表决定的。

  不过,很容易创建一个字符变量 @clist,它包含用逗号隔开的列 ID(名称)以下是外键表的 SQL 示例。

  select @clist = fokey1 || ‘,’ || fokey2 || ‘,’ ||

  . . .

  fokey15 || ‘,’ || fokey16 || ‘,0’

  from sysreferences

  where constrid =

  select @clist = left (@clist, charindex (‘,0’, @clist) - 1)

  之后,便可以通过含有 @tableid(即外键表的对象 id)以及 @clist 参数的 sp_object_access 命令有效地构建临时表:

  select @list = @clist -- WANT AN UPDATEABLE COPY OF @clist

  insert into #oa_colids -- TINYINT COLUMNS colid AND granted

  select 0, 0

  from syscolumns

  where id = @tableid

  update #oa_colids

  set colid = case (charindex (',', @clist))

  when 0 then 0

  else convert (tinyint, left (@clist, charindex (',', @clist) - 1))

  end,

  @list = substring (@clist, charindex (',', @clist) + 1, 512)

  delete #oa_colids

  where colid = 0

  在整个表格形成此键的情况下,该 insert 语句将提供足够的行。update 语句将通过表扫描对 #oa_colids 进行更新。行之间的 @list 值和大小写操作值会有所改变,这两个赋值语句的顺序很重要。delete 语句会删去所有不需要的行。

  sp_object_access 的剩余部分将通过 @tableid 、proc_role 功能以及若干系统表来更新已授权的列值。更新结束时,将返回存取指示符(若 #oa_colids 中任意获得授权的值为 0,则指示符为 0;否则,为 1)。值 1 的指示符表明,该选择权限已经足够。上述技术还可用于

  到目前为止,改变页面大小所造成的影响最大。最小的空间分配单元为:八个数据页大小。因而,2K 的页面所分配的空间为 16K,4K 的页面所分配的空间为 32K,8K 的页面所分配的空间为 64K,而 16K 的页面所分配的空间为 128K。较大的数据集会从较大的页面中受益,但较小的数据集会影响性能。

  如果您的表格很小,比方说只有几行,它仍将占用某个页面限度的最小空间。因此,页面大小 16K 与 128K 之间的差异变得更加明显。如果最初该数据全部位于一个 2K 的页面上,将其移至 16K 的页面上就意味着您最终会浪费 126K 的空间。

  如果您有很多这样的小表格,则最终结果不言而喻。这也同样适用于索引。索引有它们自己的限度。请相应地计划您修改的容量。

  如果您打算换用较大的页面以容纳几个较大的表格,则最好在转至最大的页面之前,先尝试使用一个中间尺寸的页面。另一方面,如果您想容纳较宽的行,则修改数据模型也是一种替代方案。此外,牢记大页面对数据高速缓存的影响。内存始终按照逻辑单位 2K 来分配。使用较大的页面意味着,当您使用同等大小的缓存时,只有少量的缓冲区可供使用。您需要对这些项进行调整,可向缓存增加更多内存以进行补偿。

  移植到其他供应商的数据库产品中也会导致意外的容量变化。请查阅相关文档,并向对这些产品拥有丰富经验的 DBA 咨询。举例来说,笔者曾经有一位客户,他拥有一个 2GB 小数据库。三年来,该数据库在使用过程中从未出现过容量问题。1999 年,第三方供应商通知我的客户,他们遇到了 Y2K 问题,而他们的产品升级版本不再在后台支持 Sybase ASE。该供应商建议将数据库移植到 Oracle 中。由于我对此一窍不通,于是请了一位 Oracle DBA。他建议使用 6GB 的 Oracle 数据库。

  起初,我对其中的原因感到很困惑,并惊讶地发现在六个月的移植过程中,该数据库大小将增大至 9GB。一年后,我先前的客户好不容易将容量再次修改为 18GB。读过 Brian Ceccarelli 在他的网站(网址为 www.talus software.com)上发表的评论后,我现在知道其中的原因了。看来 Oracle 没能很好地利用本地的数据类型。这个经历清楚地表明,DBA 为什么在移植时始终要将此类容量规划问题牢记在心。

  注:有些人在回顾本文前半部分随附的脚本示例时,发现笔者无意中假定存储过程 get_database_summary(在文件 dbsummary.sql 中)的页面大小为 2K。脚本以及 ISUG 网站发布的版本已经对此处进行了更正。

  结束语

  正如本文的第一部分所提到的,笔者个人使用的是用 Perl 编写的脚本。该进程的自动化程度比我们所介绍的进程要高。不过,基本构造块这里都有,它足以为更加复杂的系统奠定基础。有时您会很被动(tempdb 填充或日志出人意料变满),大多数情况下您应该尝试后退一步,找出该问题的实际根源,而不是继续处理紧急事件。总体目标是帮助 DBA 更加主动地管理他们的系统。 _

  N 列表可传递 N varchar 参数,且 update 语句中含有 2N 赋值子句。笔者还没有尝试将该技术用于多列表或可以为空的数据类型。

  在确定索引的选择性时,也有检查列权限的类似需要:如果提供了全部索引键的有效值,则可通过 select 子句返回行的平均数。(有时会将选择性定义为百分比。)唯一索引具有最佳的非寻常选择性值 1。可通过以下命令确定选择性:

  select selectivity = avg (count ())

  from
  group by , ... -- ALL OF THE INDEX KEYS

  由于使用了矢量集合的矢量聚集,因此以上为非 ANSI 索引。不过,它可以与 ASE 12.5.x 很好地兼容,并且元组关系演算对其进行了明确的定义。