我在与 Lukas Eder的Twitter 对话中偶然发现了这个问题。
尽管正确的行为是在最外层查询上应用 ORDER BY 子句,因为在这里,我们没有在最外层查询中使用 DISTINCT、GROUP BY、JOIN 或任何其他 WHERE 子句,为什么 RDBMS 不只是通过传入的数据是按内部查询排序的吗?
SELECT *
FROM (
SELECT * FROM table ORDER BY time DESC
) AS t
Run Code Online (Sandbox Code Playgroud)
在 PostgreSQL 上运行此示例时,至少,您会为内部查询和此派生表示例获得相同的执行计划,以及相同的结果集。
因此,我假设 Planner 将简单地丢弃最外层的查询,因为它是多余的,或者只是通过内部表的结果。
有没有人认为情况可能并非如此?
内联视图允许您从子查询中进行选择,就好像它是不同的表一样:
SELECT
*
FROM /* Selecting from a query instead of table */
(
SELECT
c1
FROM
t1
WHERE
c1 > 0
) a
WHERE
a.c1 < 50;
Run Code Online (Sandbox Code Playgroud)
我已经看到这使用不同的术语来引用:内联视图、WITH 子句、CTE 和派生表。对我来说,它们似乎是同一件事的不同供应商特定语法。
这是一个错误的假设吗?这些之间是否有任何技术/性能差异?
我读到派生表比临时表具有更好的性能,但无论如何许多 SQL Server 开发人员更喜欢第二个。为什么?我必须对大数据(数百万条记录)进行查询,并且我想确保我使用的是最佳选择。
CREATE TABLE A(
id BIGINT IDENTITY(1,1) NOT NULL,
field1 INT NOT NULL,
field2 VARCHAR(50) NULL,
);
CREATE TABLE B(
id INT IDENTITY(1,1) NOT NULL,
field1 VARCHAR(10) NULL,
field2 INT NULL
);
INSERT INTO A
(field1,field2)
VALUES
(1,'a'),(2,'b'),(3,'c'),(2,'d'),(5,'e'),
(6,'f'),(7,'g'),(8,'h'),(9,'i'),(2,'j');
INSERT INTO B
(field1,field2)
VALUES
('a',1),('b',2),('c',3),('d',4),('e',5),
('f',6),('g',7),('h',8),('i',9),('j',2),('k',3);
DECLARE @begin INT=0,@end INT=200;
Run Code Online (Sandbox Code Playgroud)
派生表
/*derived tables*/
SELECT
C.id,C.field1,C.field2,C.field3
FROM
(
SELECT
A.id,A.field1,A.field2,B.field2 AS field3,
ROW_NUMBER() OVER (ORDER BY A.id) AS iRow
FROM
A INNER JOIN B ON A.field1=B.id
) C …
Run Code Online (Sandbox Code Playgroud) performance sql-server-2008 sql-server derived-tables temporary-tables query-performance
首先,可更新的 CTE、派生表或视图可以直接作为目标UPDATE
,即使它具有多个基表,只要所有列都来自同一源表。
DELETE
但即使仅选择一个表中的列,它们也不能成为 a 的目标。
Msg 4405 Level 16 State 1
View or function 'x' is not updatable because the modification affects multiple base tables.
Run Code Online (Sandbox Code Playgroud)
为了绕过这个限制,我尝试MERGE
对虚拟表使用 a 。(显然,这个简单的示例可以使用DELETE...WHERE EXISTS
或通过将一个表作为合并源来编写,但这一点是正确的。使用了原始示例,ROW_NUMBER
因此这些是不可能的。)
WITH Joined AS (
SELECT t1.*
FROM t1
JOIN t2 ON t2.id1 = t1.id1
)
MERGE Joined
USING (VALUES(0)) v(dummy) ON 1=0
WHEN NOT MATCHED BY SOURCE THEN DELETE;
Run Code Online (Sandbox Code Playgroud)
这实际上是被允许的。但我发现被修改的表并不依赖于所选择的列或其顺序。这完全取决于表的连接顺序。
在我看来,这似乎是完全错误的行为。
实验THEN UPDATE
显示了更明智的行为:它取决于子句中使用的列THEN UPDATE
,与普通语句相同 …
oracle ×2
sql-server ×2
cte ×1
delete ×1
merge ×1
mysql ×1
order-by ×1
performance ×1
postgresql ×1
t-sql ×1