sql - T-SQL。更好的是:加入然后组或组然后加入
问题描述
我有 2 张桌子:
命令:
IdProduct (what is ordered - FK to Product table)
Price (what is the total price for offer)
Piece (i.e. count - how many products are ordered?)
产品:
Id
Name
并且有 2 个 SQL 语句以每件商品的最优惠价格返回商品:
声明#1:
SELECT
p.Name,
MIN (Price / Piece) AS MinPrice
FROM
[ORDER] o
JOIN
Product p ON IdProduct = p.Id
GROUP BY
p.Name
声明#2:
SELECT p.Name, t.MinPrice
FROM
(SELECT IdProduct, MIN(Price/Piece) AS MinPrice
FROM [Order]
GROUP BY IdProduct) t
JOIN
Product p ON p.Id = t.IdProduct
我在 Microsoft SQL Server Management Studio 中调查了执行计划,它们看起来非常相似,但我有几个观察结果:
为什么第一个计划使用
[order by name]
指令?即使我不使用 T-SQL Order 指令,它的输出也有按“asc”排序的产品名称这种隐含的“按名称排序”会减慢第一个 sql 的速度。当我将“按名称排序”添加到第二个 sql 时 - 它们对于执行计划成本变得相同。
我猜 sql #2 的性能应该优于 #1,因为:
一个)。它按PK(即整数)分组,而不是按名称(具有
nvarchar
列类型,而且没有索引)b)。它仅在第一个分组后才加入表,这应该最大限度地提高性能(与加入完整的 2 个表相比,因为它对第一个 sql 的预期) - 但执行计划仍然显示相同的估计执行成本。
您更喜欢哪种 SQL 语句,为什么?可能您有自己的 SQL 语句版本吗?
解决方案
就个人而言,我更喜欢陈述 2。我的理由与你所期望的完全不同。
您是否意识到您的 2 个语句不是为返回相同的结果而构建的?
第一个查询不按产品对记录进行分组,而是按产品名称对记录进行分组。在大多数数据库中,被调用name
的列从来都不是唯一的。因此,这 2 个GROUP BY
是不等价的(也许您的测试数据恰好使 2 个结果相同,但这只是在这里玩的运气)。
这是应该写的:
SELECT
p.Name,
MIN (Price / Piece) AS MinPrice
FROM
[ORDER] o
JOIN
Product p ON IdProduct = p.Id
GROUP BY
IdProduct, p.Name /* GROUP BY PK on Product */
恕我直言,第二种语法可以很好地防止这种错误。我建议那是你使用的那个。
当您使用 100 多个表而不是您自己创建和填充的 2 个表处理遗留数据库时,这将为您节省一些麻烦,更不用说第一个语句可能会在很长一段时间内正常工作,直到最终Product.name
变得非唯一。
顺便说一句,隐含order by
暗示它没有使用 PK 列。它不会减慢您的查询速度。它正在订购记录以准备GROUP BY
PS:要回答您关于性能的问题,您的第二条语句与我所写的语句应该非常相似(感谢查询规划器)。
我有时会看到第一个语句明显慢于第二个语句,但从未明显快于第二个语句(如果存在异常,它们非常罕见,以至于我错过了它们)。
PPS:由于您从 聚合数据,因此在字段中Product
添加 a可能会使性能变得更加复杂。
恐怕这是您每次开发新查询时都必须尝试的事情。WHERE
Order
推荐阅读
- javascript - 如何让 tampermonkey / 嵌入式 js 用户脚本在运行前等待?
- python - 比较列表并获取每个元素的匹配百分比
- google-apps-script - 如何在 Google 表格中的图表上创建多个图形?
- c# - 将 JSON 响应转换为 Graph.EducationAssignment 对象
- ios - SecItemCopyMatching 始终为存储的 EC 密钥返回“似乎不是有效的钥匙串项”
- c - 如何包含 Apache Avro C 头文件?
- unity3d - NullReferenceException 在 Unity 中使用 ScriptableObjects
- postgresql - 仅在 Linux 中;org.postgresql.util.PSQLException:错误:关系“table_name”不存在
- flutter - 颤动改变焦点上的边框颜色
- python - 在python中循环列名