如何强制 SQL Server 以特定顺序执行查询

Posted

技术标签:

【中文标题】如何强制 SQL Server 以特定顺序执行查询【英文标题】:How do I force SQL Server to execute a query in a particular order 【发布时间】:2009-03-13 11:49:59 【问题描述】:

我有以下问题

声明 @userId INT 声明 @siteId INT 设置@siteId = -1 设置@userId = 1828 选择 a.id 作为 alertId, a.location_id, a.alert_type_id, a.event_id, a.user_id, a.site_id, a.accepted_by FROM 警报作为 加入 alert_types AS ats ON a.alert_type_id = ats.id 加入事件 AS tr ON a.event_id = tr.event_id WHERE tr.end_Time 为空 AND tr.status_id = 0 和 ats.code = 'E' AND a.site_id in (SELECT * FROM dbo.udf_get_event_sitelist(@siteId, @userId))

此查询需要 5 到 17 秒才能运行,但在许多情况下,函数 dbo.udf_get_event_sitelist(@siteId, @userId) 不返回任何行,因此查询不会找到任何数据。

如何强制 SQL Server 先执行用户定义的函数。我很感激我可以将查询重写为存储过程并首先执行子选择,但是如果可能的话,我希望在单个 SQL 语句中完成。

【问题讨论】:

能否也请您从您的 UDF 中发布代码,我怀疑您最好重写此逻辑,也许作为子查询或 CTE。 我在这里看不到存储过程,只是一个查询和一个函数。这些是 INNER、OUTER 还是 CROSS 连接。 它们是内部联接(如果未提供联接类型,则为默认值) StingyJack 编辑删除对存储过程的引用(此代码实际上是从 SP 中提取的) 【参考方案1】:

将“FROM”表作为函数的结果集并将其他表连接到它

DECLARE @userId INT  
DECLARE @siteId INT

SET @siteId = -1  
SET @userId = 1828  

SELECT  a.id AS alertId,  
        a.location_id,  
        a.alert_type_id,  
        a.event_id,  
        a.user_id,  
        a.site_id,  
        a.accepted_by  
FROM    (SELECT * FROM dbo.udf_get_event_sitelist(@siteId, @userId)) dt
JOIN    alerts AS a ON dt.site_id=a.site_id
JOIN    alert_types AS ats ON a.alert_type_id = ats.id 
JOIN    events AS tr ON a.event_id = tr.event_id 
WHERE   tr.end_Time IS null
AND     tr.status_id = 0
AND     ats.code = 'E'

【讨论】:

谢谢迈克。我自己也得到了同样的解决方案,但还没有写出来。出于兴趣,这将大多数查询所需的时间从 5-15 秒缩短到亚秒【参考方案2】:

您可以将 udf_get_event_sitelist 的结果选择到表变量中,并且只有在 @@rowcount > 0 时才继续进行大查询

【讨论】:

【参考方案3】:

您在使用内联函数时遇到的问题是它们可以为 SELECT 中返回的每一行重新计算。这意味着,如果 SELECT 语句返回 100 行,则该函数可以执行 100 次。

您应该真正遵循 Sambo99 的建议并将其提取到一个表变量(如果您认为它需要索引,则可以是一个临时表)。

【讨论】:

我假设由于我没有将 Sub 查询与外部查询相关联,因此 SQL Server 将首先评估该条件,就像许多其他数据库引擎一样)。我想我猜错了。 这两种方式都可能发生,所以盲目地说一种方式或另一种方式是假设优化器将采取的计划。我认为在任何情况下都最好是明确的。【参考方案4】:

另外,修改您的 UDF 以仅返回 site_ID,因为我猜您不需要所有 (*) 列

SELECT * FROM dbo.udf_get_event_sitelist(@siteId, @userId)

SELECT site_id FROM dbo.udf_get_event_sitelist(@siteId, @userId)

【讨论】:

我假设 UDF 只返回一列,否则这将无效?我同意,如果指定了列,它看起来会更清晰(如果随后修改 UDF 以返回多个列,则可以防止查询被破坏)。 不仅看起来更清晰,而且会鼓励更好的实践。看到缺少指定的JOIN类型,这点肯定是要指出来的。 始终指定隐式连接类型是否被认为是一种好习惯?我知道 INNER JOIN 是默认类型,但我没有指定 JOIN 类型,因为我想要默认值。同样,我很少使用 SORT ASCENDING,因为它是隐含的。 与其把它留给下一位读者的假设(所有 f'ups 之母)不如说出来。已知默认值会更改,但可能不是这种情况。

以上是关于如何强制 SQL Server 以特定顺序执行查询的主要内容,如果未能解决你的问题,请参考以下文章

如何强制连接顺序以提高 MYSQL 中的查询性能?

SQL Server强制使用特定索引 并行度

如何编写oracle SQL查询以特定顺序获取匹配和不匹配的行对(基于键列)

如何查询我的所有视图设计以查找 SQL Server 中的特定字符串?

强制SQL Server执行计划使用并行提升在复杂查询语句下的性能

SQL Server-聚焦强制索引查询条件和Columnstore Index