0

好的,这只是理论上的,所以如果一个公正的数据库爱好者发表意见,那就太好了。

为了争论,让我们同意对于查询有“基表”这样的概念,其中一个表驱动结果集的大部分信息。想象一个查询,其中存在三个关系 - TableA、TableB 和 TableC

假设 TableA 有 100 万条记录,TableC 有 500 条记录,TableC 有 10,000 条记录。

假设查询是这样的 -

SELECT A.Col1
     , A.Col2
     , A.Col3
     , A.Col4
     , A.Col5
FROM TableA A
 LEFT JOIN TableB B ON B.ID = A.TableBID
 LEFT JOIN TableC C ON C.ID = A.TableCID

好的,显然TableA 是上面的基本关系。它是最大的表,它通过“从”连接来驱动结果集,从视觉上看,列甚至在结果集的“左侧”。(左边的东西实际上是我同事的标准)。

现在,假设 TableA 再次有 100 万行,TableB 是“连接”或“桥”表,有 500,000 行,TableC 有 1,000,000 行。因此,假设查询只是一个外连接,用于获取 TableA 和 TableC 中存在如下关系的所有列......

SELECT A.*
     , C.*
FROM TableC C
 FULL OUTER JOIN TableB B ON C.ID = B.TableAID
 FULL OUTER JOIN TableA A ON A.ID = B.TableCID

好的,鉴于最后一个查询,谁能告诉我“基本关系”是什么?我不认为有一个,但希望另一个数据库人的意见。

4

4 回答 4

4

术语“基表”有一个定义,它与您所描述的无关。“基表”几乎只是一个“表”。也就是说,它不是视图,也不是表值函数,也不是查询的结果。它作为显式表存储在数据库中。

您似乎正在掌握的内容似乎与优化策略更相关。我在优化的上下文中使用了类似的术语来描述优化器正在访问的“驱动表”。这样做的目的是区分不同的执行计划。

考虑以下查询:

from t1 join t2 using (col)

有多种不同的执行计划。以下是一些方法以及可能被认为是它们的“驱动表”(如果有的话):

for each row in t1
    for each row in t2
         compare col
-->  t1 is the "driving table"

for each row in t2
    for each row in t1
        compare col
--> t2 is the "driving table"

for each row in t1
    look up t2 value using index on t2(col)
--> t1 is the "driving table"

sort t1 by col
sort t2 by col
compare the rows in the two sorted sets
--> no "driving table"

hash t1 by col
hash t2 by col
compare the hash maps
--> no "driving table"

换句话说,“驱动”表与查询结构关系不大。它基于用于查询的优化策略。也就是说,left joins 和right joins 限制了优化路径。因此,在嵌套循环或索引查找情况下,“第一个”(或“最后一个”)表将是驱动表。

于 2018-12-08T13:11:30.310 回答
3

“驱动”表的概念实际上是关于 DBMS 如何在内部执行查询的假设。在没有任何与索引相关的偏好的情况下,基于规则的查询优化器可能会在选择执行计划时将查询中的表和连接的顺序视为重要。在基于成本的优化器下,表和连接的顺序没有任何意义,因此查询本身的结构不会告诉您首先读取哪个表或评估连接条件的顺序。

在对查询进行概念化时,将一张表作为查询的起点可能会有所帮助,但我认为这里问题的答案一定是否定的。从逻辑上讲,没有驾驶台之类的东西。

于 2018-12-12T12:57:54.843 回答
3

基表是给定的命名表值变量——数据库表。而已。在查询表达式中,它的名称是表示其值的叶表达式。“给定表变量”将更具描述性。查询可以对表使用文字表示法。将给定的命名表值常量也称为“基数”是合理的。这与某种“主”表无关。


关系模型建立在一个表上,该表包含从其(特征谓词(由列名参数化的语句模板)构成一个真实命题(语句)的行。我们提供基表行并获取查询表达式行。

作为基表名称的查询表达式带有设计者给出的谓词。

/* (person, liked) rows where [liker] likes [liked] */
/* (person, liked) rows where Likes(liker, liked) */
SELECT * FROM Likes

作为表文字的查询表达式在列等于值方面具有特定的谓词。

/* (person) rows where
    person = 'Bob'
*/
SELECT * FROM (VALUES ('Bob')) dummy (person)

否则,查询表达式具有根据其关系运算符从其组成表表达式谓词构建的谓词。

  • 每个代数算子都对应一个特定的逻辑算子。
    NATURAL JOIN&&&&& AND
    RESTRICTtheta_ _ _ _ANDtheta
    UNIONOR
    MINUSAND NOT
    PROJECTall butCEXISTS C
    etc

/* (person) rows where
    (FOR SOME liked, Likes(person, liked))
OR  person = 'Bob'
*/
    SELECT liker AS person
    FROM Likes
UNION
    VALUES ('Bob')

/* (person, liked) rows where
FOR SOME [values for] l1.*, l2.*,
        person = l1.liker AND liked = l2.liked
    AND Likes(l1.liker, l1.liked)
    AND Likes(l2.liker, l2.liked)
    AND l1.liked = l2.liker
    AND person = 'Bob'
    AND NOT Likes(l1.liked, 'Ed')
*/
Likes l1 INNER JOIN Likes l2
ON l1.liked = l2.liker
WHERE l1.liker = 'Bob'
AND NOT (l1.liked, 'Ed') IN (SELECT * FROM Likes)

在确定包含查询表达式的谓词时,如何使用基本、文字或运算符调用查询表达式没有区别。

是否有任何经验法则可以根据人类可读的描述构造 SQL 查询?
关系代数 - 重新编码列值

于 2018-12-08T03:06:45.007 回答
2

让我提出一个观点,其中基表FROM子句中的第一个(即不是JOINed 表)。在一个语句可以用一个表或另一个表作为基表来编写的情况下,我们会说有两个(或更多)基表

在您的第一个查询中,基表是TableA. 如果在查询中反转TableATableC,则不能保证获得相同的结果,因为LEFT JOIN.

在第二个查询中,当您使用FULL JOINs 时,可以在不更改结果的情况下反转所有 3 个表,因此这确实是所有表都是基表的查询的用例。

于 2018-12-08T01:28:49.330 回答