是否在SQL视图中选择了列?

时间:2013-06-14 11:16:40

标签: sql sql-server sql-server-2008-r2 sql-optimization sqlperformance

我无法找到合适的关键字来搜索答案,所以如果已经回答,请道歉。

考虑以下SQL视图:

CREATE VIEW View1 AS
SELECT Column1
      ,Column2
      ,(SELECT SUM(Column3) FROM Table2 WHERE Table2.ID = Table1.ID)  -- Subquery
FROM Table1

如果我运行以下查询,子查询是执行还是SQL Server优化查询?

SELECT Column1 FROM View1

我从性能的角度看这个,比如说,如果视图有很多子查询(如果内部选择引用一个大表,聚合可能需要很长时间)。

我正在使用SQL Server 2008 R2,但我很想知道2012年或MySQL的答案是否不同。

感谢。

2 个答案:

答案 0 :(得分:4)

如前所述,这取决于您的DBMS(版本和提供商),以确定检查执行计划。这表明对于SQL-Server 2008,子查询未执行:

enter image description here

正如您在未选择Column3的顶层计划中所看到的,该计划只是从table1中选择,在包含Column3的底部计划中,查询了table2。

In SQL-Server 2008 R2它没有被执行。

In SQL-Server 2012它没有被执行;

In MySQL它被执行,两个查询都生成相同的计划:

enter image description here

进一步详细说明,它还取决于您的确切查询以及您的DBMS。例如:

CREATE VIEW View2
AS
    SELECT  t.ID, t.Column1, t.Column2, t2.Column3
    FROM    Table1 t
            LEFT JOIN
            (   SELECT  ID, Column3 = SUM(Column3)
                FROM    Table2
                GROUP BY ID
            ) t2
                ON t2.ID = t.ID
GO
SELECT  Column1, Column2
FROM    View2;

SELECT  Column1, Column2, Column3
FROM    View2;

enter image description here

在这种情况下,您会得到与相关子查询类似的结果。如果未选择column3,则计划仅显示table1中的select,因为优化器知道子查询LEFT JOIN具有t2与table1中的select没有关系,也没有使用任何列,所以它不会打扰它。如果您将LEFT JOIN更改为INNER JOIN,例如

CREATE VIEW View3
AS
    SELECT  t.ID, t.Column1, t.Column2, t2.Column3
    FROM    Table1 t
            INNER JOIN
            (   SELECT  ID, Column3 = SUM(Column3)
                FROM    Table2
                GROUP BY ID
            ) t2
                ON t2.ID = t.ID
GO
SELECT  Column1, Column2
FROM    View3;

SELECT  Column1, Column2, Column3
FROM    View3;

enter image description here

这两个查询的查询计划显示,由于第二个查询中未使用聚合列,因此优化器实际上将视图更改为:

SELECT  t.ID, t.Column1, t.Column2
FROM    Table1 t
        INNER JOIN
        (   SELECT  DISTINCT ID
            FROM    Table2
        ) t2
            ON t2.ID = t.ID;

正如表2中Distinct Sort的外观和Stream Aggregate的删除所示。

总而言之,这取决于。

答案 1 :(得分:-1)

视图只是一个定义,就像查询中的临时表一样。 首先,将执行视图后面的查询,然后在视图上进行选择。所以是的,子查询将被执行。如果你不想这样做,你应该创建一个没有子查询的新视图。