sql-server - 在非规范化表中分组
问题描述
我们有一个包含非规范化数据的表,其中存储事件,其中包括以下字段:ProductId | 产品名称 | 子类别 ID
它们直接相互依赖,因此对于特定的 productid,Productname 和 subcategoryid 可能只有一个值。由于我们存储事件,因此我们有许多行将包含与上述三个字段相关的相同信息。
我们现在正在设计一个查询来获取唯一的 productid、productname 和 subcategoryid。这些查询将返回相同的实体:
select ProductId from VisitEvents
group by ProductId
作为这个:
select productid, productname, subcategoryid from visitevents
group by productid, productname, subcategoryid
然而,后者要慢几个数量级。除了第一个查询中分组的内容之外,有没有办法投影其他字段?
解决方案
我对速度问题的潜在原因发表了评论(主要可能是由于排序所需的读取和处理增加)。
但是,我对您的问题的主要理解是
- 您的数据实际上只是按 productid 分组,但由于它是非规范化的,因此它具有与 productid 直接相关的其他列
- 因为您要对所有三个字段进行分组,所以速度很慢 - 您希望通过仅对 productid 进行分组来加快速度
答案 1:索引
如果您在这些列上放置索引,它将已经被预先排序。但是,我的猜测是您的索引已经非常密集,因此更多的索引可能会导致问题。如果没有,请尝试在所有 3 个字段上添加索引,或者如果某些字段太大(例如,nvarchar(4000)),则在其余字段上添加索引,并“包含”大字段。
调整查询
对于这些,我们接受我们必须在查询中进行排序。问题是如何减少处理和/或读取。
如果没有统计数据和/或执行计划,这可能很难 - 但这里有一些建议。
我相信下面的第一种方法不会真正起作用,但值得一试。
select productid, MAX(productname) as productname, MAX(subcategoryid) as subcategoryid
from visitevents
group by productid
我希望你看到我正在尝试做的事情 - 将分组减少到一个字段。然而,由于它仍然需要进行排序以获得最大值,它可能仍然很慢(尽管它们没有被排序在一起,它可能会快一点)。
另一种方法是对 productid 进行排序/组并获取任何相应的值(您不在乎哪个)。一种方法是
; WITH cte AS
(select productid, productname, subcategoryid,
ROW_NUMBER() OVER (PARTITION BY productid ORDER BY productid) AS rn
from visitevents
)
SELECT productid, productname, subcategoryid
FROM cte
WHERE cte.rn = 1
对于上述内容,它获取所有数据,按 productid 对其进行排序,然后(有点随机)为该组中的每一行分配行号。然后它只获取所有第一行。
它很丑。它有点滥用窗口函数(PARTITION BY productid ORDER BY productid
???)根据定义,这个 ORDER BY 什么都不做,但包含在内是因为您必须在 ROW_NUMBER 中有一个 ORDER BY。
什么都不做是你想要的——不想把 CPU 周期花在额外的种类上。所以希望它可能会有所帮助。
推荐阅读
- git - 是否可以更换开发分支?
- javascript - 上传图片到服务器不返回数据
- python - Pandas 在第一个索引上选择多索引范围?
- oracle - 一个Oracle11g的数据库每天都关掉有没有坏处。位于 AWS EC2 实例上的数据库
- vue.js - Vuejs触发点击下一个孩子
- javascript - 在 JavaScript 中将 Angular 模块降级为 AngularJS
- android - 是否可以针对 Android 28(例如`targetSdkVersion 28`)并同时使用 appcompat-v7 和 Firebase?
- linux - 在 bash 中查找文件失败
- mysql - 将重复的行转置为mysql中的列
- javascript - JS 错误 - 为什么在内部声明 x (var x=1) 时出现意外标记?