我需要在同一个表上使用2种不同类型的连接(比如ADDRESS
和USER
)。我可以制作2个表(BILLING_ADDRESS
和SHIPPING_ADDRESS
),它们都有3列(ID
,USER_ID
,ADDRESS_ID
),或者我可以创建一个表格(CUSTOMER_ADDRESS
)包含类型列(ID
,USER_ID
,ADDRESS_ID
,ADDRESS_TYPE
)。
对于DRY编码实践,我只考虑单个表,但这意味着当我编译2个列表时,我将不得不进行两次全表扫描。
select address.* from customer_addresses, address where user_id = 1 and address_type = 'Billing'
和
select address.* from customer_addresses, address where user_id = 1 and address_type = 'Shipping'
两者都依赖于customer_addresses表的全表扫描。
如果我们有1000个客户地址,则表示已扫描了2000条记录,以查找该客户的所有地址。
如果我执行2个不同的表,则只扫描1000个客户地址,因为shipping_addresses表只保存800个地址/客户记录,billing_addresses表保存另外200个。
因此,对于性能,我不得不说2个不同的表。对于DRY,我必须使用单表。业界对此有何看法?
答案 0 :(得分:2)
送货地址和帐单邮寄地址可能不同。例如,帐单邮寄地址可能是邮政信箱,但送货地址通常不能。同样,送货地址可能包含其他信息,例如联系人姓名,联系电话和下车说明。我只是提到这一点,因为您需要确定差异是否足以创建单独的实体,或者只是在地址表中有几个单独的字段。
这只是为了让您知道可能还有其他字段。
我认为这是您建议的查询(修复了join
语法):
select a.*
from customer_addresses ca join
address a
on ca.address_id = a.address_id
where ca.user_id = 1 and ca.address_type = 'Billing';
这不需要使用智能数据设计进行全表扫描。正如Barmar在评论中指出的那样,你应该对这些表有一个合适的索引。在这种情况下,您需要的索引是customer_address(user_id, address_type)
和address(address_id)
。如果数据库仅对SELECT
查询执行全表扫描,则SQL将是一种不太有用的语言,可能不会在任何地方使用。
答案 1 :(得分:0)
单个表格允许更多灵活性。例如,将来您可能决定允许客户存储备用送货地址,并在下订单时选择一个。然后,您可以添加address_type = 'Alternate Shipping Address'
,您不必添加另一张整张表。
此设计应该对性能影响很小。 user_id
上的索引会将查询范围缩小到需要扫描所需地址类型的几行。
答案 2 :(得分:0)
如果满足您的所有需求,单个表会好得多,在这种情况下,您提到的两个方案都会redundant data
查看normalization以获取更多信息,在这种情况下我认为如果您有一个表ADDRESS (ID, USER_ID, SHIPPING_ADDRESS_ID, BILLING_ADDRESS_ID).
比地址的拖车表更加坚固,在这种情况下,您无法到达forth normal form