继续 - 在查询完成之前查看 FIRST_ROWS

Posted

技术标签:

【中文标题】继续 - 在查询完成之前查看 FIRST_ROWS【英文标题】:Continuation - Viewing FIRST_ROWS before query completes 【发布时间】:2010-04-05 05:17:20 【问题描述】:

我已经确定了我的用户通常使用的查询结构。创建复合索引来支持这些结构并提供 FIRST_ROWS 功能对我来说有意义吗?

如果我从 SE 迁移到 IDS,我将失去使用 C-ISAM 调用编写低级函数的能力,但会获得 FIRST_ROWS 以及其他好处,例如:用于索引扫描的 SET-READS (onconfig USE_[KO]BATCHEDREAD )、优化器指令、并行查询等。


评论信息

当铺生产表通过以下方式查询:customer.name char(30) 使用通配符 (LASSURF* 查找 LASTNAME SURNAME, FIRSTNAME) 或通过pawns.ticket_number INT 查询。客户和典当通过以下方式连接:customer.name =pawns.name,而不是 customer.serial =pawns.fk。 trx 日期超过 1 年的典当被移动到另一个硬盘上的不同数据库中的历史表 (>500K nrows)。历史索引按 trx_date 降序排列。这就是 ad-hoc 复合查询构造发挥作用的地方。

一旦发现客户的典当交易,该行就会在客户进行抵押或赎回 pymt 时更新。如果客户在 90 天内未进行 pymt,用户将手动更新他们将没收的典当。当客户赎回典当或因缺少 pymt 而没收典当时,pawns.status 变为非活动状态。当他们的 trx 日期超过 1 年时,不活动的人会从典当表中移出到历史表中,因此此应用程序中不会发生大规模更新。当铺每天早上营业前都会运行此程序。

ISQL 2.10.06E (SE-DOS16M protected mode) pawns table optimization - 
 once-daily, before start of business, procedure

 unload to "U:\UNL\ACTIVES.UNL"
    select * from pawns where pawns.status = "A"
  order by pawns.cust_name, pawns.trx_date;

 unload to "U:\UNL\INACTIVE.UNL"
    select * from pawns
     where pawns.status <> "A"
       and pawns.trx_date >= (today - 365)
  order by pawns.cust_name, pawns.trx_date desc;

 unload to "U:\UNL\HISTORIC.UNL"
    select * from pawns
     where pawns.status <> "A"
       and pawns.trx_date < (today - 365)
  order by pawns.trx_date desc;

 drop table pawns;

 create table pawns
 (
     trx_num serial,
     cust_name char(30),
     status char(1),
     trx_date date,
 . . . ) in "S:\PAWNSHOP.DBS\PAWNS";

 load from "U:\UNL\ACTIVES.UNL" insert into pawns;         500:600 nrows avg.
 load from "U:\UNL\INACTIVE.UNL" insert into pawns;        6500:7000 nrows avg.
 load from "U:\UNL\HISTORIC.UNL" insert into dss:historic; >500K nrows

 create cluster index pa_cust_idx on pawns (cust_name);

 this groups each customers pawns together, actives in
  oldest trx_date order first, then inactive pawns within the last year in most 
  recent trx_date order. inactives older than 1 year are loaded into historic 
  table in a separate database, on a separate hard disk. historic table 
  optimization is done on a weekly basis for DSS queries.

 create unique index pa_trx_num_idx on pawns (trx_num);
 create index pa_trx_date_idx on pawns (trx_date);
 create index pa_status_idx on pawns (status);

 grant statements...

 update statistics;

【问题讨论】:

这是***.com/questions/2563358 的延续,但这个问题与其他问题截然不同。 我对我的应用程序的一些功能做了一些澄清,并重新格式化了 SQL proc 示例以便于查看。历史表与我在查询继续时查看 FIRST_ROWS 结果的愿望有关,并为需要这些功能的任何其他应用程序建议此功能。这也会影响我决定是升级到 IDS 还是留在 SE。 本论坛中的“Informix Subquery's with FIRST option”是否会更深入地了解 FIRST_ROWS 讨论,还是仅返回查询完成后指定的第一个 nrows? 【参考方案1】:

没有简单的是/否答案 - 这是一种平衡行为,就像许多性能问题一样。

与索引相关的两个主要成本必须与收益相平衡。

    在表中添加、删除、修改行时,必须维护索引。成本虽不高,但也不容忽视。 索引占用磁盘空间。

仅仅因为要考虑更多索引而优化查询时也会产生少量开销。

良好索引的主要好处是,当索引可以发挥良好效果时,可以极大地提高选择数据的性能。

如果您的表不是很不稳定,并且经常使用索引可以提供帮助的条件进行搜索,那么假设磁盘空间不是问题,那么创建复合索引可能是有意义的。

如果您的表非常不稳定,或者很少使用特定索引(但在使用它的少数情况下是有益的),那么您或许应该权衡较慢查询的几乎一次性成本与在可以使用的少数情况下存储和维护索引的成本。

有一本非常好的关于索引设计的书:Relational Database Index Design and the Optimizers,作者是 Lahdenmäki 和 Leach(它也相当昂贵)。


在最新的评论中,弗兰克说:

[L]正在寻找一些东西。正如已经说过的,最简单的做法是允许 Informix 在获得行后开始返回它们。 (甲骨文默认这样做。)弗兰克所要求的更大的图景与谷歌的相似。好的,当谈到网络上的搜索索引时,它真的可以追溯到 Alta Vista 和 90 年代。这个想法是您可以进行快速搜索,在报告搜索中返回的“数量”行的同时选择前 n 个事物。 (好像谷歌报告的数字是准确的。)

弗兰克的这一补充评论在这个问题的上下文中更有意义。

显然,除非 SQL 语句强制 Informix 进行排序,否则它会在获得结果后立即提供结果;它总是有。 FIRST_ROWS 优化提示向 IDS 表明,如果它可以选择两个查询计划,并且其中一个会让它比另一个更快地生成第一行,那么它应该更喜欢快速生成第一行的那个,即使它总体上比替代品更贵。即使在没有提示的情况下,IDS 仍然会尝试尽快使数据可用 - 它也只是尝试尽可能高效地完成。

准备好查询后,您可以估计可能返回的行数 - 您可以将其用作指标(少数、相当多、非常多)。另外,您可以快速独立地发现您正在搜索的主表中的行数。鉴于此元数据,您当然可以使用带有滚动游标的技术在数据库中为您提供一个后备存储,其中包含您感兴趣的行的主键值。您可以随时加载包含显示数据的数组一组有趣的行显示给用户。根据用户要求,您可以安排显示另一个充满信息的页面。在程序的某个时刻,您会发现滚动光标中的数据已到达末尾。显然,如果你做 FETCH LAST,你就会强迫它发生。如果你只是多做几次 FETCH NEXT,那么你最终会得到一个 NOTFOUND 条件。

自 80 年代后期以来,Informix(IDS 及其前身、OnLine、Turbo、SE 和 I4GL)都可以实现所有这些。 FIRST_ROWS 优化是更新的;它仍然只是对优化器的提示,通常对优化器的作用没有多大影响。

【讨论】:

当铺生产表通过以下方式查询:customer.name char(30) 使用通配符(LASSURF* 查找 LASTNAME SURNAME、FIRSTNAME)或通过pawns.ticket_number INT 查询.客户和典当通过以下方式连接:customer.name =pawns.name,而不是 customer.serial =pawns.fk.. trx 日期超过 1 年的典当被移动到另一个数据库中的历史表(>500K nrows),在另一个硬盘。历史索引按 trx_date 降序排列。这是 ad-hoc 复合查询构造的地方。 一旦发现客户典当交易,当客户产生利息或赎回 pymt 时,将更新该行。如果客户在 90 天内没有进行 pymt,则该典当被没收,行被更新,典当状态变为非活动状态并最终在一年后移至历史表,因此该应用程序不会发生大规模更新。当铺每天早上营业前都会运行这个过程:(请参阅接下来的 3 部分 cmets,空间已用完)。 ISQL 2.10.06E (SE-DOS) pawns table optimization - daily startup procedure 卸载到 "U:\UNL\ACTIVES.UNL" select * from pawns wherepawns.status = "A"按pawns.cust_name、pawns.trx_date排序;卸载到 "U:\UNL\INACTIVE.UNL" select * from pawns wherepawns.status IN ("I","F","R","T") andpawns.trx_date >= (today - 365) order通过pawns.cust_name,pawns.trx_date desc;卸载到 "U:\UNL\HISTORIC.UNL" 从pawns 中选择 * 其中pawns.status IN ("I","F","R","T") 和pawns.trx_date 丢桌棋子;在“S:\PAWNSHOP.DBS\PAWNS”中创建表pawns(trx_num serial、cust_name char(30)、status char(1)、trx_date date,...);从 "U:\UNL\ACTIVES.UNL" 加载插入到 pawn;从 "U:\UNL\INACTIVE.UNL" 加载插入到 pawn;从“U:\UNL\HISTORIC.UNL”加载插入到历史;在pawns(cust_name)上创建集群索引pa_cust_idx; 这将每个客户典当分组在一起,首先按最旧的 trx_date 顺序活动,然后 按最近的 trx_date 顺序,在过去一年内不活跃的棋子。超过 1 年的非活动数据被加载到单独硬盘上的历史表中。每周对 DSS 查询进行历史表优化。 在pawns (trx_num) 上创建唯一索引pa_trx_num_idx;在pawns(trx_date)上创建索引pa_trx_date_idx;在pawns(状态)上创建索引pa_status_idx; grant statements... 更新统计信息;

以上是关于继续 - 在查询完成之前查看 FIRST_ROWS的主要内容,如果未能解决你的问题,请参考以下文章

Javascript在继续之前等待结果

在查询结束前开始查看查询结果

Python多线程线程在继续之前不等待.join()

我希望代码在继续之前等待上一行完成

函数在继续循环之前不等待条件完成

如何在继续之前等待所有 multiprocessing.Processes 完成?