【问题标题】:SQL efficient solution for mutilple joins (could be 10 joins) on same table (lookup table)同一表(查找表)上的多个连接(可能是 10 个连接)的 SQL 高效解决方案
【发布时间】:2016-04-20 20:37:23
【问题描述】:

我们已经实现了一个包含 ID 和文本字段的查找表。然后我的表只包含不同字段值的 LookupID。比如……

表格

  • TableID、StatusID、TypeID、DocID

值看起来像这样

  • 1、2、3、4

查找表

  • 查找ID,文本

值看起来像这样

  • 1、某值
  • 2,我的状态文本
  • 3、我的类型文本
  • 4、我的文档文本

我需要知道的是,这是否是查询这些表的最有效解决方案(使用显示的文本而不是 ID 创建数据的 sql 视图)

SELECT T.TableID, L1.Text as StatusText, L2.Text as TypeText, L3.Text as DocText
FROM Table T
LEFT JOIN LookupTable L1 on L1.LookupID = T.StatusID
LEFT JOIN LookupTable L2 on L2.LookupID = T.TypeID
LEFT JOIN LookupTable L3 on L3.LookupID = T.DocID

... 或者子查询更适合这个解决方案?像这样。

SELECT T.TableID,
  (SELECT L.Text FROM LookupTable L WHERE L.LookupID = T.StatusID) as StatusText,
  (SELECT L.Text FROM LookupTable L WHERE L.LookupID = T.TypeID) as TypeText,
  (SELECT L.Text FROM LookupTable L WHERE L.LookupID = T.DocID) as DocText
FROM Table T

... 或者有更好的解决方案吗?请记住,对于这个示例,我只加入了 3 次,并且需要加入 10 次或更多次。

【问题讨论】:

  • 当您只提出假设情况时,很难评论最佳解决方案是什么。无论如何,使用单个“LookupTable”的想法似乎是一个真的坏主意。 JOINs 也几乎总是比您拥有的子查询方法更好。除此之外,很难评论。设计没有通过气味测试,但我不能说它什么时候只是“Table”和“SomeValue”等。
  • 您是否测试了您提供的两个可能查询的性能?我遇到过相关子查询表现更好的案例。
  • 很久以前我在一个应用程序中建立了一个 MasterXref 表,并为该系统的生命周期而后悔。使用起来真是太糟糕了,当您最终在整个地方的查询中一遍又一遍地访问同一张表时,性能非常具有挑战性。我再也不会那样做了。
  • @trincot 表格太小,无法真正确定性能。我可能会创建几个大表,看看两者之间的性能是否不同。
  • 每次查找都有一个单独的表。它更容易编码和维护。您也没有一个表成为系统中最繁忙的表来检索人类可读的显示值。

标签: sql sql-server left-join


【解决方案1】:

您最好的选择可能是为数据库中的每个单独实体创建单独的查找表。如果您需要为单个查找类型添加附加属性(例如,现在您需要跟踪每个州的州鸟,但这肯定与汽车模型无关),这将为您在未来提供更好的灵活性。以我的经验,“通用”数据库设计模式通常很糟糕。有目的的设计。

一旦你有了这个,只要你有适当的索引,有多个JOINs 几乎总是(如果不是总是)比子查询执行得更好:

SELECT
    P.person_id,
    S.state_name,
    G.movie_genre_name,
    ...
FROM
    Person P
INNER JOIN [State] S ON S.state_id = P.home_state_id
INNER JOIN Movie_Genre G ON G.movie_genre_id = P.favorite_movie_genre_id
...

另外,请记住,系统中的每个列表都不一定是查找表。例如,性别之类的东西可以通过CHECK CONSTRAINT 简单地维护:

gender VARCHAR(15) NULL CONSTRAINT CHK_Person_Gender CHECK (gender IN ('Male', 'Female', 'Transgender'))

或:

severity VARCHAR(10) NOT NULL CONSTRAINT CHK_Ticket_Severity CHECK (severity IN ('High', 'Medium', 'Low'))

这与基本上只是一个名称的列表有关。具有附加属性的项目的列表或可能随时间频繁更改的列表应放入表中。

【讨论】:

    【解决方案2】:

    您是否考虑过使用UNPIVOT 来破解它?

    【讨论】:

    • 我没有。我会调查的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-07
    • 2018-05-16
    • 2017-08-20
    • 2014-10-16
    • 1970-01-01
    • 2013-05-11
    • 2015-05-18
    相关资源
    最近更新 更多