[英]SQL counting and multiple subqueries on huge tables
我有一些SQL表,分别命名为FOS,关键字和PRef。 它们的结构和关系如下:
+------------------+ +------------------+ +-----------------+
| FOS | | keywords | | PRef |
+------------------+ +------------------+ +-----------------+
|fosID (PK) |--+ |pkID (PK) | +---|pID1 (PK) |
|fosName | +---|fosID(FK) | +---|pID2 (PK) |
+------------------+ |paperID (FK) |--+ +-----------------+
( 53k+ rows) +------------------+ ( 952M+ rows)
( 157M+ rows)
目前,我可以通过向查询提供单个fosID来做到这一点,但是由于fos表包含超过1k条记录,因此我没有足够的人力来手动提供每个fosID并获取其对应的rowCount然后合并所有结果
declare @fosID varchar(10)='1234567890';--my fosID
select fos.fosID,fos.fosName,count(*) as rowCount
from PRef pr left join FOS fos on fos.fosID=@fosID
where
pr.pID1 in(SELECT paperID FROM keywords k where k.fosID=@fosID)
OR pr.pID2 in(SELECT paperID FROM keywords k where k.fosID=@fosID)
group by fos.fosID,fos.fosName
然后给出正确的结果为:
+----------+--------+----------+
|fosID |fosName |rowCount |
+----------+--------+----------+
|1234567890|name1 |34 |
+----------+--------+----------+
现在,我想获取所有fos项目的列表以及PRef中53k + fos项目的每个记录的数量。
我试图将where k.fosID=@fieldID
的部分修改为where k.fosID=@fieldID
的部分where k.fosID in (select fosID from FOS)
但产生的计数较少。
关于如何解决这个问题有什么建议吗?
PS我现在正在看游标,但是性能确实...真的很慢
编辑1:预期结果:
+----------+--------+----------+
|fosID |fosName |rowCount |
+----------+--------+----------+
|1234567890|name1 |34 |
|1234567891|name2 |3 |
|1234567892|name3 |23 |
|..... |.... |... |
+----------+--------+----------+
(exact same number of rows as table FOS)
您可以只修改子查询以使用关联的子查询
select fos.fosID, fos.fosName, count(*) as rowCount
from PRef pr cross join
FOS fos
where pr.pID1 in (SELECT paperID FROM keywords k where k.fosID = fos.fosID) OR
pr.pID2 in (SELECT paperID FROM keywords k where k.fosID = fos.fosID)
group by fos.fosID, fos.fosName;
我的猜测是性能会很差。
这是一种选择:
select fos.*, kp.cnt
from fos outer apply
(select count(*) as cnt
from keywords k join
pref pr
on k.paperID in (pr.pID1, pf.pID2) and
k.fosID = fos.fosID
) kp;
我认为这也将具有非常差的性能特征。
如果可以分别设置每个ID,则SQL Server应该能够提出更好的执行计划:
select fos.*, (kp1.cnt + kp2.cnt)
from fos outer apply
(select count(*) as cnt
from keywords k join
pref pr
on k.paperID = pr.pID1 and
k.fosID = fos.fosID
) kp1 outer apply
(select count(*) as cnt
from keywords k join
pref pr
on k.paperID = pr.pID2 and
k.fosID = fos.fosID
) kp2;
首先,我怀疑您可以通过检查表中的数据类型来获得重大改进。 看来您只使用数字的varchar(10)吗?
在小型表上不会注意到这种荒谬,但是在900M行上可能浪费超过5GB,从而影响存储,内存和性能。
第二个FOS
仅真正用于查找fosName
并且在53k行中是工作的较小部分。 因此,首先要正确获取每个fosID的计数; 然后加入名字。
;with CountPerFos as (
SELECT k.fosID, COUNT(*) AS fosCount
FROM PRef r
INNER JOIN keywords k ON
r.PID1 = k.paperID
OR r.PID2 = k.paperID
GROUP BY k.fosID
)
SELECT c.fosID, f.fosName,
--Need to handle fosIDs missing from CTE above
COALESCE(c.fosCount, 0)
FROM FOS f
LEFT OUTER JOIN CountPerFos c
f.fosID = c.fosID
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.