4

成像我们在 RDBMS 中有 2 个表,INVOICE 和 INVOICE_LINE_ITEMS,INVOICE 和 INVOICE_LINE_ITEMS 之间存在一对多的关系。

发票 (1) --------> (*) INVOICE_LINE_ITEMS

上述实体现在需要存储在Cassandra中,为此我们可以遵循 2 种方法,

  1. 带有 PRIMARY KEY (invoice_id, invoice_line_item_id) 的非规范化表,对于一张发票,会有多个 line_item_id。

  2. 带有 SET<FROZEN<INVOICE_LINE_ITEMS_UDT>> 的 INVOICE 行

  3. 有 2 个表并负责更新 2 个表并在 DAO 代码中加入查询结果

用例是,

  1. 用户可以创建发票并不断添加、更新和删除行

  2. 用户可以使用 invoice 或 invoice_line_udt 属性进行搜索并获取发票详细信息(使用 DSE 搜索 solr_query)

  3. INVOICE(标题)可能包含 20 个属性,每个项目(invoice_line)可能包含大约 30 多个属性,一个大的 UDT,每个集合可能有大约 1000 行。

问题:

  1. 由于序列化和反序列化,使用冻结集合会影响读写性能。考虑到 UDT 包含 30 多个字段和最多 1000 个集合中的项目,这是一个好的方法还是数据模型?

  2. 因为存在序列化和反序列化,所以每次更新记录或分区时都会替换 UDT 的集合。列更新会创建墓碑吗?考虑到我们在项目(UDT 集合)中有很多更新,这会产生问题吗?

这是方法 1 的 CQL:(具有 UDT 集合的发票标题行)

CREATE TYPE IF NOT EXISTS comment_udt (
    created_on timestamp,
  user text,
  comment_type text,
  comment text
);

CREATE TYPE IF NOT EXISTS invoice_line_udt ( ---TO REPRESENT EACH ITEM ---
invoice_line_id text,
invoice_line_number int,
parent_id text,

item_id text,
item_name text,
item_type text,

uplift_start_end_indicator text,
uplift_start_date timestamp,
uplift_end_date timestamp,
bol_number text,
ap_only text,

uom_code text,
gross_net_indicator text,
gross_quantity decimal,
net_quantity decimal,
unit_cost decimal,
extended_cost decimal,

available_quantity decimal,
total_cost_adjustment decimal,
total_quantity_adjustment decimal,
total_variance decimal,

alt_quantity decimal,
alt_quantity_uom_code text,
adj_density decimal,

location_id text,
location_name text,
origin_location_id text,
origin_location_name text,
intermediate_location_id text,
intermediate_location_name text,
dest_location_id text,
dest_location_name text,

aircraft_tail_number text,
flight_number text,
aircraft_type text,

carrier_id text,
carrier_name text,

created_on timestamp,
created_by text,
updated_on timestamp,
updated_by text,
status text,

matched_tier_name text,
matched_on text,
workflow_action text,

adj_reason text,
credit_reason text,
hold_reason text,
delete_reason text,
ap_only_reason text
);


CREATE TABLE IF NOT EXISTS invoice_by_id ( -- MAIN TABLE --
invoice_id text,
parent_id text,
segment text,
invoice_number text,
invoice_type text,
source text,
ap_only text,
invoice_date timestamp,
received_date timestamp,
due_date timestamp,

vendor_id text,
vendor_name text,
vendor_site_id text,
vendor_site_name text,

currency_code text,
local_currency_code text,
exchange_rate decimal,
exchange_rate_date timestamp,
extended_cost decimal,
early_pay_discount decimal,
payment_method text,
invoice_amount decimal,
total_tolerance decimal,
total_variance decimal,

location_id text,
location_name text,
dest_location_override text,

company_id text,
company_name text,
org_id text,

sold_to_number text,
ship_to_number text,
ref_po_number text,
sanction_indicator text,

created_on timestamp,
created_by text,
updated_on timestamp,
updated_by text,
manually_assigned text,
assigned_user text,
assigned_group text,
workflow_process_id text,
version int,
comments set<frozen<comment_udt>>, 
status text,

lines set<frozen<invoice_line_udt>>,-- COLLECTION OF UDTs --

PRIMARY KEY (invoice_id, invoice_type));

这是方法 2 的脚本:(非规范化发票和行在一个分区但多行)

CREATE TABLE wfs_eam_ap_matching.invoice_and_lines_copy1 ( 
invoice_id uuid, 
invoice_line_id uuid, 
record_type text, 
active boolean, 
adj_density decimal, 
adj_reason text, 
aircraft_tail_number text, 
aircraft_type text, 
alt_quantity decimal, 
alt_quantity_uom_code text, 
ap_only boolean, 
ap_only_reason text, 
assignment_group text, 
available_quantity decimal, 
bol_number text, 
cancel_reason text, 
carrier_id uuid, 
carrier_name text, 
comments LIST<FROZEN<comment_udt>>, 
company_id uuid, 
company_name text, 
created_by text, 
created_on timestamp, 
credit_reason text, 
dest_location_id uuid, 
dest_location_name text, 
dest_location_override boolean, 
dom_intl_indicator text, 
due_date timestamp, 
early_pay_discount decimal, 
exchange_rate decimal, 
exchange_rate_date timestamp, 
extended_cost decimal, 
flight_number text, 
fob_point text, 
gross_net_indicator text, 
gross_quantity decimal, 
hold_reason text, 
intermediate_location_id uuid, 
intermediate_location_name text, 
invoice_currency_code text, 
invoice_date timestamp, 
invoice_line_number int, 
invoice_number text, 
invoice_type text, 
item_id uuid, 
item_name text, 
item_type text, 
local_currency_code text, 
location_id uuid, 
location_name text, 
manually_assigned boolean, 
matched_on timestamp, 
matched_pos text, 
matched_tier_name text, 
net_quantity decimal, 
org_id int, 
origin_location_id uuid, 
origin_location_name text, 
parent_id uuid, 
payment_method text, 
received_date timestamp, 
ref_po_number text, 
sanction_indicator text, 
segment text, 
ship_to_number text, 
sold_to_number text, 
solr_query text, 
source text, 
status text, 
total_tolerance decimal, 
total_variance decimal, 
unique_identifier FROZEN<TUPLE<text, text>>, 
unit_cost decimal, 
uom_code text, 
updated_by text, 
updated_on timestamp, 
uplift_end_date timestamp, 
uplift_start_date timestamp, 
uplift_start_end_indicator text, 
user_assignee text, 
vendor_id uuid, 
vendor_name text, 
vendor_site_id uuid, 
vendor_site_name text, 
version int, 
workflow_process_id text, 
PRIMARY KEY (invoice_id, invoice_line_id, record_type) 
);

注意:我们使用 datastax cassandra + DSE 搜索。它不支持静态列,因此我们没有使用它。此外,为了提供真实的图片,我列出了包含很多列的表和 UDT,并最终创建了一个很长的问题。

4

0 回答 0