customer.pk_name объединяет транзакции.fk_name против customer.pk_id [серийный номер] присоединяется к транзакциям.fk_id [целое число] - PullRequest
2 голосов
/ 18 июня 2010

Заявление в ломбард (любая РСУБД):

Отношение один-ко-многим, где у каждого клиента (мастера) может быть много транзакций (подробно).

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 [serial] к Transactions.id [integer].

Когда клиент закладывает товар, клерк запрашивает мастера, используя подстановочные знаки в имени. Запрос обычно возвращает нескольких клиентов, клерк прокручивает до тех пор, пока не найдет нужное имя, вводит «D», чтобы перейти в детальную таблицу транзакций, все транзакции автоматически запрашиваются, затем клерк вводит «А», чтобы добавить новую транзакцию.

Проблема с использованием customer.id для присоединения транзакции.id заключается в том, что, хотя таблица клиентов поддерживается в отсортированном порядке имен, кластеризация таблицы транзакций по группам fk_id транзакции по fk_id, но они не в том же порядке, что и имя клиента, поэтому, когда клерк прокручивает имена клиентов в мастер-системе, система должна перепрыгнуть через место, чтобы найти кластерные транзакции, принадлежащие каждому клиенту. По мере добавления каждого нового клиента этому клиенту присваивается следующий идентификатор, но новые клиенты не отображаются в алфавитном порядке. Я экспериментировал с использованием id-соединений и подтвердил снижение производительности.

Недостатки использования объединений имен и объединений идентификаторов заключаются в том, что если вы меняете имя клиента, объединение с его транзакциями прерывается, поэтому я не разрешаю обновлять имя. В любом случае, как часто нужно менять имя клиента? Другой недостаток: name требует 30 символов, где id - INT, поэтому .dat и .idx больше. Каждое утро выполняется процедура sql, которая выгружает клиента и транзакции в отсортированном порядке имен, удаляет / заново создает таблицы, загружает выгруженные данные, и все индексы воссоздаются, что сохраняет производительность оптимизированной.

Как я могу использовать соединения идентификаторов вместо соединений имен и при этом сохранять порядок кластеризованных транзакций по имени, если транзакция не имеет столбца имени?

Ниже приведен пример расположения данных в customer.dat и Transactions.dat при использовании имени pk / fk, как описано в приведенной выше схеме:

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:

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

Хорошо, теперь имейте в виду, что мой экран выполнения на 1 странице включает все столбцы клиентов и все столбцы транзакций, и есть инструкция master / detail, которая, когда клерк запрашивает имя клиента, первая строка транзакции, принадлежащая этому клиенту. автоматически отображается. Затем клерк нажимает «D», чтобы сделать транзакции активной таблицей, и «A», чтобы добавить новую транзакцию, или клерк может прокручивать все транзакции клиентов, чтобы обновить одну из них, или просто предоставить клиенту информацию.

При использовании метода имени pk / fk, когда клерк прокручивает имена клиентов, чтобы найти нужного клиента, ответ мгновенный. Принимая во внимание, что при использовании метода идентификатора pk / fk время отклика отстает, даже с поддерживаемой индексацией, потому что движок должен перейти в разные места в таблице транзакций, чтобы найти соответствующую группу транзакций, принадлежащих каждому клиенту, поскольку клерк прокручивает имя каждого клиента в мастере!

Таким образом, кажется, что строки транзакций клиента сгруппированы вместе и в том же отсортированном порядке, что и строки клиентов, что позволяет индексации быстрее находить транзакции, в отличие от необходимости перемещаться по разрозненным группам транзакций каждого клиента.Если бы каждый клиент мог вспомнить своего клиента, то есть номер, тогда моя проблема была бы академической, но в реальном мире мы даже дали каждому клиенту i.d. карточка с номером клиента, но большинство из них потеряли свои карточки!

Вот пример ежедневной реорганизации, выполняемой каждое утро перед открытием ломбарда:

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

2 голосов
/ 18 июня 2010

Они правы. Присоединение к текстовому полю CHAR (30), в частности, содержащему данные имени человека, будет медленным, чрезвычайно неэффективным и невероятно хрупким. Люди меняют свои имена (очевидный пример - брак), и у нескольких людей может быть одно и то же имя.

Вы хотите создать соответствующие индексы в своих таблицах для поддержки порядка, в котором вы хотите, чтобы данные отображались, и забыть о кластеризации. Ваша процедура оптимизации производительности звучит как катастрофа в поисках места, которое должно произойти. Извините, но удаление / создание таких таблиц вызывает проблемы.

Я бы начал с УНИКАЛЬНОГО ИНДЕКСА на customer.id, УНИКАЛЬНОГО ИНДЕКСА для транзакции.ticket_number и ИНДЕКСА (для производительности, а не для кардинальности, поэтому обеспечение уникальности не очень важно) для транзакций (id, ticket_number DESC) и возьми это оттуда. Данные возвращаются из таблицы транзакций в порядке их появления в индексе.

Я бы рассмотрел кластеризацию только тогда, когда все другие возможности оптимизации запросов были исчерпаны.

0 голосов
/ 28 июня 2010

Количество записей в вашей базе данных является тривиальным для любого из продуктов, которые вы упоминаете.Правильно структурированная база данных не будет иметь проблем с возвратом транзакций по идентификатору.

Правильно структурированная в этом случае означает, что столбец идентификатора является первичным ключом в таблице клиентов и внешним ключом в таблице транзакций.В общем, внешние ключи автоматически индексируются, но если вы используете продукт, в котором этого не происходит, столбец customer_id в таблице транзакций должен быть проиндексирован.Не включайте поле имени в таблицу транзакций.

Предполагая, что вы используете индекс, не беспокойтесь о том, что база данных "перепрыгнет через все".База данных не такая простая часть программного обеспечения, что они работают таким образом.

0 голосов
/ 18 июня 2010

Вы столкнетесь с некоторыми проблемами с людьми с длинными именами, которые не будут вписываться в CHAR (30), особенно если вы включаете полное отчество.

Я думаю, что вы слишком озабочены кластеризацией транзакций по имени. В описанном вами сценарии вы выбираете список клиентов (поэтому я вижу некоторые требования, чтобы сделать клиентов легко доступными по имени, хотя индекса должно быть достаточно). Затем транзакции доступны для конкретного клиента, поэтому не должно иметь значения, сгруппированы ли они по идентификатору или имени клиента.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...