Smu*_*mur 10 sql-server-2005 sql-server query statistics
这是从临时表中进行的简单选择,在其主键上加入现有表,两个子选择使用 top 1 引用连接表。
在代码中:
SELECT
TempTable.Col1,
TempTable.Col2,
TempTable.Col3,
JoinedTable.Col1,
JoinedTable.Col2,
(
SELECT TOP 1
ThirdTable.Col1 -- Which is ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeColumn = JoinedTable.SomeColumn
) as ThirdTableColumn1,
(
SELECT TOP 1
ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
) as ThirdTableColumn2,
FROM
#TempTable as TempTable
LEFT JOIN
JoinedTable
ON (TempTable.PKColumn1 = JoinedTable.PKColumn1 AND
TempTable.PKColumn2 = JoinedTable.PKColumn2)
WHERE
JoinedTable.WhereColumn IN (1, 3)
Run Code Online (Sandbox Code Playgroud)
这是我的查询的精确副本。
如果我删除两个子选择,它运行得很好而且很快。通过两个子选择,我每秒得到大约 100 条记录,这对于这个查询来说非常慢,因为它应该返回近一百万条记录。
我已经检查过是否每张表都有一个主键,他们都有。它们都有重要列的索引和统计信息,就像那些 WHERE 子句中的那些,以及 JOIN 子句中的那些。唯一没有定义主键和索引的表是临时表,但这也不是问题,因为它与慢速子选择无关,而且正如我所提到的,没有子选择它运行得很好。
如果没有这些,TOP 1
它会返回多个结果,并引发错误。
帮助,有人吗?
编辑:
所以执行计划告诉我我缺少一个索引。我已经创建了它,并重新创建了一些其他索引。过了一会儿,执行计划开始使用它们,查询现在运行得很快。唯一的问题是我没有成功在另一台服务器上再次执行相同的查询。所以我的解决方案是提示 SQL Server 将使用哪个索引。
小智 7
我认为在一百万条记录查询中,您必须避免诸如OUTER JOINS
. 我建议你使用UNION ALL
而不是LEFT JOIN
. 只要我认为CROSS APPLY
select子句中的子查询效率更高,我就会修改Conard Frix编写的查询,我认为这是正确的。
现在:当我开始修改您的查询时,我注意到您有一个 WHERE 子句说: JoinedTable.WhereColumn IN (1, 3)
。在这种情况下,如果该字段为空,则条件将变为假。那么为什么在过滤空值行时使用 LEFT JOIN 呢?只需替换LEFT JOIN
With INNER JOIN
,我保证它会变得更快。
关于指数:
请注意,当您在表上有索引时,请说
table1(a int, b nvarchar)
Run Code Online (Sandbox Code Playgroud)
你的索引是:
nonclustered index ix1 on table1(a)
Run Code Online (Sandbox Code Playgroud)
你想做这样的事情:
select a,b from table1
where a < 10
Run Code Online (Sandbox Code Playgroud)
在您的索引中您没有包含该列b
,那么会发生什么?
如果 sql-server 使用您的索引,它将必须在索引中搜索,称为“索引查找”,然后引用主表以获取列b
,称为“查找”。此过程可能比扫描表本身花费的时间长得多:“表扫描”。
但根据 sql-server 的统计数据,在这种情况下,它可能根本不使用您的索引。
所以首先检查Execution Plan
索引是否被使用。
如果是或否两者,请更改您的索引以包括您选择的所有列。像这样说:
nonclustered index ix1 on table1(a) include(b)
Run Code Online (Sandbox Code Playgroud)
在这种情况下,将不需要查找,并且您的查询将执行得更快。
小智 6
它是导致缓慢返回的列选择中的子选择。您应该尝试在左连接中使用您的子选择,或者使用我在下面定义的派生表。
对第三个表的两个实例使用左连接
SELECT
TempTable.Col1,
TempTable.Col2,
TempTable.Col3,
JoinedTable.Col1,
JoinedTable.Col2,
ThirdTable.Col1 AS ThirdTableColumn1,
ThirdTable2.Col1 AS ThirdTableColumn2
FROM #TempTable as TempTable
LEFT JOIN JoinedTable ON (TempTable.PKColumn1 = JoinedTable.PKColumn2 AND
TempTable.PKColumn 2 = JoinedTable.PKColumn2)
LEFT JOIN ThirdTable ON ThirdTable.SomeColumn = JoinedTable.SomeColumn
LEFT JOIN ThirdTable ThirdTable2 ON ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
WHERE
JoinedTable.WhereColumn IN (1, 3)
Run Code Online (Sandbox Code Playgroud)
使用派生表
SELECT
TempTable.Col1,
TempTable.Col2,
TempTable.Col3,
DerivedTable.Col1,
DerivedTable.Col2,
DerivedTable.ThirdTableColumn1,
DerivedTable.ThirdTableColumn2
FROM #TempTable as TempTable
LEFT JOIN (SELECT
JoinedTable.PKColumn2,
JoinedTable.Col1,
JoinedTable.Col2,
JoinedTable.WhereColumn,
ThirdTable.Col1 AS ThirdTableColumn1,
ThirdTable2.Col1 AS ThirdTableColumn2
FROM JoinedTable
LEFT JOIN ThirdTable ON ThirdTable.SomeColumn = JoinedTable.SomeColumn
LEFT JOIN ThirdTable ThirdTable2 ON ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn)
DerivedTable ON (TempTable.PKColumn1 = DerivedTable .PKColumn2 AND
TempTable.PKColumn2 = DerivedTable.PKColumn2)
WHERE
DerivedTable.WhereColumn IN (1, 3)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
59307 次 |
最近记录: |