2

質屋アプリケーション (任意の RDBMS):

各顧客 (マスター) が多くのトランザクション (詳細) を持つことができる 1 対多の関係。

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; 

何人かの人々が、これは master を詳細に結合する正しい方法ではないと私に言いました。彼らは、私は常に customer.id[serial] を transactions.id[integer] に結合するべきだと言いました。

顧客が商品をポーンすると、店員は名前にワイルドカードを使用してマスターに問い合わせます。クエリは通常、複数の顧客を返します。事務員は適切な名前が見つかるまでスクロールし、'D' を入力して詳細トランザクション テーブルに変更します。すべてのトランザクションが自動的にクエリされ、次に事務員が 'A' を入力して新しいトランザクションを追加します。

transaction.id に結合する customer.id を使用する際の問題は、顧客テーブルがソートされた名前順に維持されているにもかかわらず、トランザクション テーブルを fk_id でクラスタ化すると、トランザクションが fk_id でグループ化されますが、それらは顧客名と同じ順序ではないことです。店員がマスターで顧客名をスクロールしているとき、システムは各顧客に属するクラスター化された取引を見つけるためにあちこちジャンプしなければなりません。新しい顧客が追加されるたびに、次の ID がその顧客に割り当てられますが、新しい顧客はアルファベット順に表示されません。id join を使って実験したところ、パフォーマンスの低下を確認しました。

名前結合と ID 結合を使用することの欠点は、顧客名を変更すると、トランザクションとの結合が切断されるため、名前の更新を許可しないことです。とにかく、どのくらいの頻度で顧客の名前を変更する必要がありますか? もう 1 つの欠点は、id が INT である name には 30 文字が必要であるため、.dat と .idx の方が大きくなることです。毎朝 sql proc が実行され、顧客とトランザクションがソートされた名前順にアンロードされ、テーブルが削除/再作成され、アンロードされたデータがロードされ、すべてのインデックスが再作成されてパフォーマンスが最適化されます。

トランザクションに名前列がない場合、名前結合の代わりに ID 結合を使用し、クラスター化されたトランザクションの順序を名前で保持するにはどうすればよいですか?

以下は、上記のスキーマで説明されているように、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

そのため、店員が顧客のマスター名でワイルドカード クエリを実行すると、顧客のトランザクションが自動的にクエリされ、現在のリストに返された名前をスクロールすると、顧客のトランザクションがマスターと同じソート順であるため、すばやく表示されます。

次の例は、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

OK、ここで、1 ページの実行画面にはすべての顧客列とすべてのトランザクション列が含まれていることに注意してください。店員が顧客名でクエリを実行すると、その顧客に属する最初のトランザクション行が自動的に表示されるマスター/詳細指示があります。 . 次に、店員は「D」を押して取引をアクティブなテーブルにし、「A」を押して新しい取引を追加します。または、店員はすべての顧客取引をスクロールして特定の取引を更新するか、顧客に情報を提供するだけです。

pk/fk name メソッドを使用する場合、店員が顧客名をスクロールして目的の顧客を見つけると、応答は即座に行われます。一方、pk/fk id メソッドを使用する場合は、サポートされているインデックス作成を使用しても、応答時間が遅くなります。これは、店員が各顧客名をスクロールするときに、各顧客に属する対応するトランザクション グループを見つけるために、エンジンがトランザクション テーブル内のさまざまな場所にジャンプする必要があるためです。マスターで!

したがって、顧客のトランザクション行をグループ化し、顧客行と同じソート順にすることで、各顧客トランザクションの散在するグループ全体をジャンプする必要があるのではなく、インデックス作成でトランザクションをより迅速に見つけることができます。各顧客が自分の顧客 ID 番号を覚えていれば、私の問題は学術的なものになりますが、実際には、各顧客に顧客番号が記載された ID カードを渡しましたが、ほとんどの顧客がカードを紛失しました!

以下は、質屋が営業を開始する前に毎朝実行される毎日の reorg の例です。

 {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; 

時間があれば、誰にでもこれをテストするように挑戦します! .. 大きなテーブルがあると、より顕著になります。

4

3 に答える 3

2

彼らは正しい。CHAR(30) テキスト フィールド (特に人名データを含むフィールド) での結合は、遅く、非常に非効率的で、信じられないほど脆弱です。人々は自分の名前を変更します (結婚は明らかな例です)。複数の人が同じ名前を持つことができます。

テーブルに適切なインデックスを作成して、データを表示する順序をサポートし、クラスタリングを忘れたいとします。あなたのパフォーマンス最適化手順は、起こる場所を探す災害のように聞こえます。申し訳ありませんが、そのようなテーブルを削除/作成すると、問題が発生します。

customer.id の UNIQUE INDEX、transaction.ticket_number の UNIQUE INDEX、およびトランザクション (id, ticket_number DESC) の INDEX (カーディナリティではなくパフォーマンスのため、一意性を強制することはそれほど重要ではありません) から始めて、それを取得します。そこの。データは、インデックスに表示される順序でトランザクション テーブルから返されます。

クエリ最適化の他のすべての手段が使い果たされた場合にのみ、クラスタリングを検討します。

于 2010-06-18T02:41:14.557 に答える
0

特にフルミドルネームを含める場合は、CHAR(30)に収まらない長い名前の人に問題が発生します。

名前によるトランザクションのクラスタリングに過度に関心があると思います。説明したシナリオでは、顧客のリストを選択します(したがって、インデックスで十分なはずですが、名前で顧客に簡単にアクセスできるようにするための要件を確認できます)。次に、特定の顧客のトランザクションにアクセスするため、トランザクションが顧客IDまたは顧客名のどちらでクラスター化されているかは関係ありません。

于 2010-06-18T03:25:47.713 に答える
0

データベースにあるレコードの数は、あなたが言及したどの製品についても些細なことです。適切に構造化されたデータベースでは、トランザクションを ID で返すことに問題はありません。

この場合、適切に構造化されているということは、ID 列が customer テーブルの主キーであり、transaction テーブルの外部キーであることを意味します。通常、外部キーは自動的にインデックス化されますが、それが行われない製品を使用している場合は、トランザクション テーブルの customer_id 列をインデックス化する必要があります。name フィールドをトランザクション テーブルに含めないでください。

インデックスを使用していると仮定すると、データベースが「いたるところにジャンプする」ことを心配する必要はありません。データベースは、そのように動作するような単純なソフトウェアではありません。

于 2010-06-28T03:33:00.607 に答える