代码之家  ›  专栏  ›  技术社区  ›  Pat James

customer.pk_name joining transactions.fk_name vs.customer.pk_id[serial]joining transactions.fk_id[integer]

  •  2
  • Pat James  · 技术社区  · 5 年前

    当铺应用程序(任何RDBMS):

    一对多关系,其中每个客户(主)可以有多个事务(细节)。

    customer(
    id serial,
    pk_name char(30), {PATERNAL-NAME MATERNAL-NAME, FIRST-NAME MIDDLE-NAME-INITIAL}
    [...]
    );
    unique index on id;
    unique cluster index on pk_name;
    
    
    transaction(
    fk_name char(30),
    tran_type char(1), 
    ticket_number serial,
    [...]
    );
    dups cluster index on fk_name;
    unique index on ticket_number; 
    

    有几个人告诉我这不是加入大师的正确方式。他们说我应该一直把customer.id[序列号]加入到transactions.id[整数]中。

    当顾客典当商品时,店员会用通配符查询主人的名字。查询通常返回多个客户,职员滚动直到找到正确的名称,输入“d”更改为“明细交易表”,自动查询所有交易,然后职员输入“a”添加新交易。

    使用customer.id joining transaction.id的问题是,虽然customer表是按已排序的名称顺序维护的,但是按fk_id组对transaction表进行集群 根据fk_id进行的交易,但它们的顺序与客户名称不同,因此当职员在主控形状中滚动客户名称时,系统必须跳到整个位置以定位属于每个客户的群集交易。当添加每个新客户时,下一个ID将分配给该客户,但新客户不会按字母顺序显示。我尝试使用ID连接,并确认性能下降。

    使用名称联接与ID联接的缺点是,如果您更改客户名称,则与他们的事务的联接将被切断,因此我不允许更新名称。无论如何,多久需要更改一个客户的名字?另一个回调是name需要30个字符,其中id是int,所以.dat和.idx更大。每天早上执行一个SQL过程,该过程按已排序的名称顺序卸载客户和事务,删除/重新创建表,加载已卸载的数据,并重新创建所有索引,以保持性能优化。

    如果事务没有名称列,如何使用id join而不是name join,并且仍然按名称保留集群事务顺序?

    以下是使用pk/fk名称时数据如何位于customer.dat和transactions.dat中的示例,如上述模式中所述:

    customer.id customer.pk_name               transaction.fk_name            transaction.ticket_number
    ----------- ------------------------------ ------------------------------ -------------
              2|ACEVEDO BERMUDEZ, FRANCISCO J. ACEVEDO BERMUDEZ, FRANCISCO J.|123456
                                               ACEVEDO BERMUDEZ, FRANCISCO J.|123789
    
              3|ANDUJAR RODRIGUEZ, WILFREDO C. ANDUJAR RODRIGUEZ, WILFREDO C.|101010
                                               ANDUJAR RODRIGUEZ, WILFREDO C.|121212
    
              1|CASTILLO DIAZ, FRANKLIN J.     CASTILLO DIAZ, FRANKLIN J.    |232323
                                               CASTILLO DIAZ, FRANKLIN J.    |343434
    

    因此,当Clerk Wilcard按客户主名称查询时,由于客户交易与主名称的排序顺序相同,因此当Clerk滚动浏览返回到当前列表中的名称时,会自动查询并快速显示客户交易。

    现在,下面的示例是使用pk/fk id的相同数据:

    customer.pk_id customer.name                  transactions.fk_id transactions.ticket_#
    -------------- ------------------------------ ------------------ ---------------------
                 2|ACEVEDO BERMUDEZ, FRANCISCO J.                  1|232323
                                                                   1|343434
    
                 3|ANDUJAR RODRIGUEZ, WILFREDO C.                  2|123456
                                                                   2|123789
    
                 1|CASTILLO DIAZ, FRANKLIN J.                      3|101010
                                                                   3|121212
    

    好的,现在请记住,我的执行单页屏幕包括所有客户列和所有交易列,并且有一个主/详细说明,当职员按客户名称查询时,将自动显示属于该客户的第一个交易行。然后,业务员将按“D”使交易成为活动表,然后按“A”添加新交易,或者业务员可以滚动浏览所有客户交易以更新一个特定的交易,或者只向客户提供信息。

    当使用pk/fk name方法时,当职员滚动客户名称以查找所需的客户时,立即响应。然而,当使用pk/fk id方法时,响应时间会滞后,即使使用支持的索引,因为引擎必须跳转到Transactions表中的不同位置,以定位属于每个客户的相应事务组,因为书记员在m中滚动每个客户名称。紫菀!

    因此,似乎可以将客户的事务行分组在一起,并按照与客户行相同的排序顺序进行排序,这样索引可以更快地定位事务,而不必跳过每个客户事务的分散组。 如果每个客户都记得他们的客户身份证号码,那么我的问题将是学术性的,但在现实世界中,我们甚至给每个客户一张身份证,上面写着他们的客户号码,但大多数客户的信用卡都丢了!

    以下是典当行开业前每天早上执行的每日重组示例:

     {ISQL-SE (customer and transactions table reorg - once-daily, before start of    
      business, procedure}
    
     unload to "U:\UNL\CUSTOMERS.UNL"
        select * from customer
      order by customer.pk_name; 
    
     unload to "U:\UNL\TRAN_ACTIVES.UNL" 
        select * from transaction where transaction.status = "A" 
      order by transaction.fk_name, transaction.trx_date; 
    
     unload to "U:\UNL\TRAN_INACTIVES.UNL" 
        select * from transaction
         where transaction.status != "A" 
           and transaction.trx_date >= (today - 365) 
      order by transaction.fk_name, transaction.trx_date desc; 
    
     unload to "U:\UNL\TRAN_HISTORIC.UNL" 
        select * from transaction 
         where transaction.status != "A" 
           and transaction.trx_date < (today - 365) 
      order by transaction.trx_date desc; 
    
     drop table customer;     
    
     drop table transaction;
    
     create table customer
     (
      id serial,
      pk_name char(30),
      [...]
     ) 
     in "S:\PAWNSHOP.DBS\CUSTOMER";
    
    
     create table transaction
     ( 
      fk_name char(30),
      ticket_number serial,
      tran_type char(1), 
      status char(1), 
      trx_date date, 
      [...]
     )
     in "S:\PAWNSHOP.DBS\TRANSACTION"; 
    
     load from "U:\UNL\CUSTOMERS.UNL"      insert into customer     {>4800 nrows}
     load from "U:\UNL\TRAN_ACTIVES.UNL"   insert into transaction; {500:600 nrows avg.} 
     load from "U:\UNL\TRAN_INACTIVES.UNL" insert into transaction; {6500:7000 nrows avg.} 
     load from "U:\UNL\TRAN_HISTORIC.UNL"  insert into dss:historic;{>500K nrows} 
    
     create unique cluster index cust_pk_name_idx on customer(pk_name);
     create        cluster index tran_cust_idx    on transaction(fk_name); 
    
     {this groups each customers transactions together, actives in 
      oldest trx_date order first, then inactive transactions 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 tran_ticket_num_idx on transaction(ticket_num); 
     create        index tran_trx_date_idx   on transaction(trx_date); 
     create        index tran_status_idx     on transaction(status); 
     [...;]
    
     [grant statements...;] 
    
     update statistics; 
    

    如果你有时间,我会挑战任何人来测试这个!…当你有一张大桌子的时候,它更引人注目。

    3 回复  |  直到 14 年前
        1
  •  2
  •   RET    14 年前

    他们是对的。加入一个char(30)文本字段——尤其是包含人名数据的字段——会很慢,效率非常低,而且非常脆弱。人们确实会改变自己的名字(婚姻就是一个明显的例子),而且多个人可以有相同的名字。

    您希望在表上创建适当的索引,以支持数据显示的顺序,并忽略集群。您的性能优化过程听起来像是在寻找一个发生的地方的灾难。抱歉,删除/创建这样的表会带来麻烦。

    我将从customer.id上的唯一索引、transaction.ticket\u编号上的唯一索引和事务(id、ticket\u number desc)上的索引(用于性能而不是基数,因此强制实现不太重要的唯一性)开始,并从中获取它。从事务表返回的数据按其在索引中显示的顺序排列。

    我只会在所有其他查询优化方法都用尽时考虑集群。

        2
  •  0
  •   Gary Myers    14 年前

    你会遇到一些长名字的人的问题,这些长名字不适合字符(30),特别是如果你包括一个完整的中间名。

    我认为您过于关注按名称集群事务。在您描述的场景中,您选择了一个客户列表(这样我就可以看到一些要求,使客户可以通过名称轻松访问,尽管索引应该足够)。然后访问特定客户的事务,所以不管它们是由客户ID还是客户名称集群。

        3
  •  0
  •   Larry Lustig    14 年前

    对于您提到的任何产品,您在数据库中拥有的记录数都是微不足道的。一个结构正确的数据库按ID返回事务不会有问题。

    在这种情况下,正确的结构意味着id列是客户表中的主键,是事务表中的外键。通常情况下,会自动为外键编制索引,但如果您使用的产品中没有这种情况,则必须为事务表中的客户ID列编制索引。不要在事务表中包含名称字段。

    假设您使用的是索引,那么不要担心数据库“到处乱跳”。数据库不是那么简单的软件,它们以这种方式运行。