为啥来自 VIEW 的 SELECT * 比来自同一个 VIEW 的 SELECT(特定列)执行得更快?
Posted
技术标签:
【中文标题】为啥来自 VIEW 的 SELECT * 比来自同一个 VIEW 的 SELECT(特定列)执行得更快?【英文标题】:Why is SELECT * from a VIEW executing faster than a SELECT (specific columns) from that same VIEW?为什么来自 VIEW 的 SELECT * 比来自同一个 VIEW 的 SELECT(特定列)执行得更快? 【发布时间】:2018-02-27 10:19:58 【问题描述】:我正在使用SQL Server 2012
。我有一个名为MyView
的VIEW
,我有2 个T_SQL
查询从VIEW
中提取数据。
查询 1 非常简单,如下所示:
SELECT *
FROM MyView
WHERE StayDate >= '2018-03-01'
上述查询在大约 28 秒内执行并返回 151,000 行。
查询 2 如下所示:
SELECT [Col A], [Col B], [Col C], [Col D], [Col E]
FROM MyView
WHERE StayDate >= '2018-03-01'
查询 2 的执行时间不确定。我不得不在大约 8 分钟后取消执行!!
我的问题是我需要将查询 2 用于特定任务。是什么导致了执行时间的这种差异?
VIEW
'MyView' 有几个与其他表的连接和一些内置的CASE
语句。我认为这个问题与VIEW
本身无关,否则这两个查询在执行过程中的行为方式或多或少是相同的。
我该如何处理这个问题?
【问题讨论】:
会不会是缓存结果? 您可以查看每个查询的估计执行计划吗? 您可以查看查询计划并将其粘贴到此处。估计的和实际的。请记住,使用*
可能会导致您的查询不使用索引,即使它们已经到位,请查看blog article。
如果您没有查询某些列,并且优化器能够证明它们不会影响结果(行数和行数都不存在),它将得出不同的 (更轻量级)计划完全忽略这些列。你可能有一个基数估计问题,服务器在提出一个轻量级计划时,认为某些东西会变得非常便宜,而事实证明并非如此,并且完整的计划根本不会尝试使用那个出乎意料的昂贵的东西,因此轻量级计划最终变得更重。可以更新统计信息吗?
如果网速好,如果指定列,连续流所有页面不是比检索部分更快吗?
【参考方案1】:
当您执行查询时,您的代码会传递给 SQL 查询优化器。它创建执行计划并将其缓存到内存池。当您再次执行相同的查询时,它会使用该执行计划并更快地检索信息。有时,如果两个查询以相同的执行计划结束,它们都可以使用内存池中缓存的一个。
由于视图只不过是一个存储的代码(字面意思就是你保存和执行一个 sql 文件),它应该被重复使用。正因为如此,您完全可以期望有一些缓存的 EP 用于视图。
唉,这里不是这样。
【讨论】:
解决办法是什么?索引视图? 如果有视图,为什么还需要执行查询?对我来说,解决方案是只使用视图 - 在选择、连接等中。如果您希望查询快速工作,您可以尝试通过 StayDate 将索引添加到 StayDate 列或分区。【参考方案2】:您的服务器可能出于某种原因决定采用另一个执行计划。我不知道正确的解决方案,但您可能应该更新统计信息或其他内容。
以下是我遇到类似问题时使用的一些解决方法示例:
SELECT [Col A], [Col B], [Col C], [Col D], [Col E]
FROM MyView
WHERE StayDate >= '2018-03-01'
option(recompile)
这将忽略统计数据并即时计算一个新的执行计划,希望不会是慢的一个
SELECT *
INTO #temp
FROM MyView
WHERE StayDate >= '2018-03-01'
SELECT [Col A], [Col B], [Col C], [Col D], [Col E]
FROM #temp
WHERE StayDate >= '2018-03-01'
也许它会在插入语句中保持快速执行,然后您可以从那里提取数据,我猜这些数据将包含更少的行
【讨论】:
以上是关于为啥来自 VIEW 的 SELECT * 比来自同一个 VIEW 的 SELECT(特定列)执行得更快?的主要内容,如果未能解决你的问题,请参考以下文章
为啥“SELECT DISTINCT a, b FROM...”返回的记录少于“SELECT DISTINCT A + '|' + B 来自...”?
MySQL SELECT 来自 1 个表的结果,但根据另一个表排除结果?
在单个外部 SELECT 查询中使用来自 SELECT 子查询的两个聚合值