简体   繁体   English

查询优化器和FK约束

[英]Query Optimizer and FK constraints

I have read that if you add a FK using WITH NOCHECK, the query optimizer will not use this FK in any query plan it generates. 我已经读过,如果使用WITH NOCHECK添加FK,查询优化器将不会在它生成的任何查询计划中使用此FK。 That got me to thinking about how and why would the query optimizer even consider a FK when generating a query plan? 这让我想到了查询优化器在生成查询计划时如何以及为什么会考虑FK? What benefit is there to the query engine if a FK is in place? 如果有FK,查询引擎有什么好处?

If the foreign key is "trusted", SQL Server can use the fact that the columns targeted by the constraint are in a unique index on the other table. 如果外键是“受信任的”,则SQL Server可以使用约束所针对的列位于另一个表的唯一索引中的事实。 If you have a join with the table the FK is targeting and you only use the columns present in the key, it can remove the join. 如果您有与FK定位的表的联接,并且您只使用密钥中的列,则可以删除联接。

For example, let's say you have two tables: Order and Product , and the Order table has a ProductId that is a foreign key to Product.Id . 例如,假设您有两个表: OrderProductOrder表有一个ProductId ,它是Product.Id的外键。 Then, the optimizer know that this query: 然后,优化器知道以下查询:

SELECT Order.Id, Product.Id
FROM Order
LEFT OUTER JOIN Product ON Product.Id = Order.ProductId

... is the same as this query: ...与以下查询相同:

SELECT Order.Id, Order.ProductId
FROM Order

.. and the extra join to Product can be removed. ..和Product的多余联接可以删除。 It can do that since it knows there will be at most one row in Product for each row in Order , and the values will be the same, so removing the join will not affect the query. 之所以可以这样做,是因为它知道Order每一行中Product最多会有一行,并且值将是相同的,因此删除联接不会影响查询。

If Order.ProductId is NOT NULL, then it would be able to do the same for an INNER JOIN. 如果Order.ProductId为NOT NULL,那么它将能够为INNER JOIN执行相同的操作。 If it's nullable, it can't since it doesn't know that there will be a row in Product , so the join could cause Order rows to be dropped; 如果它可以为空,则它不能,因为它不知道Product会有一行,所以连接可能导致Order行被删除; it's not the same. 这是不一样的。

However, if you add Product.Name to the SELECT clause, then it can't remove the join in either case. 但是,如果将Product.Name添加到SELECT子句中,则在任何一种情况下都无法删除该联接。

Yeah, I know: it doesn't seem very useful. 是的,我知道:它似乎没有用。 In practice, I haven't really seen too many cases where this actually makes a difference. 在实践中,我并没有真正看到太多的情况,这实际上有所作为。 Usually it's only a factor for dynamically generated SQL or code generation where the joins are fixed and only the SELECT clause changes. 通常,这只是动态生成的SQL或代码生成的一个因素,其中联接是固定的,只有SELECT子句会更改。

You can read about this here: 你可以在这里阅读:

http://explainextended.com/2009/10/15/constraints-and-the-optimizer-in-sql-server-foreign-key/ http://explainextended.com/2009/10/15/constraints-and-the-optimizer-in-sql-server-foreign-key/

As for why WITH NOCHECK makes a difference, when that is specified the key is not "trusted", which means that perhaps not all values in the column satisfy the constraint. 至于为什么WITH NOCHECK有所不同,当指定键时,键不是“可信”的,这意味着列中的所有值可能都不满足约束。 WITH NOCHECK only enforces the constraint on new data; WITH NOCHECK仅对数据WITH NOCHECK约束; any old data might violate the assumption, so SQL Server plays it safe and keeps the join there. 任何旧数据都可能违反该假设,因此SQL Server可以安全地使用它并保持连接。

What may happen is that if you have a query that join other foreign key table, and if there is a foreign key constraint, the query engine can take advantage of using the foreign table index. 可能发生的情况是,如果您有一个连接其他外键表的查询,并且如果存在外键约束,则查询引擎可以利用外部表索引。

You can test it out by looking at the query execution plan in SQL Server Management Studio. 您可以通过查看SQL Server Management Studio中的查询执行计划来对其进行测试。 It is under Query->Include Actual Execution Plan. 它位于“查询”->“包含实际执行计划”下。 Try one with FK and one WITH NOCHECK and see the difference. 尝试一个用FK和一个WITH NOCHECK看看差异。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM