HQL查询导致磁盘空间不足异常

时间:2019-02-22 15:11:59

标签: java sql sql-server hql

我有以下SQL查询,已将其翻译为HQL:

SELECT f.date,
    f.name,
    SUM(f.seats) 
FROM Foo f 
WHERE EXISTS (  SELECT 1 
                FROM Foo fh 
                WHERE f.start + f.end IN (  SELECT fl.start + fl.end 
                                                            FROM Foo fl 
                                                            WHERE fl.date BETWEEN dateadd(yy,-1,fh.date) 
                                                                AND fh.date 
                                                                AND fl.name = '<name>') 
                    AND f.date = fh.date 
                    AND fh.date >= '2016-01-01'
                    AND fh.name = '<name>' ) 
    AND f.date >= '2016-01-01'
GROUP BY f.date,
    f.name 
ORDER BY f.date ASC,
    SUM(f.seats) DESC

在我的应用程序中,此查询导致标题错误:

Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Could not allocate a new page for database 'TEMPDB' because of insufficient disk space in filegroup 'DEFAULT'. Create the necessary space by dropping objects in the filegroup, adding additional files to the filegroup, or setting autogrowth on for existing files in the filegroup.
    at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:216)
    at com.microsoft.sqlserver.jdbc.SQLServerResultSet$FetchBuffer.nextRow(SQLServerResultSet.java:4853)
    at com.microsoft.sqlserver.jdbc.SQLServerResultSet.fetchBufferNext(SQLServerResultSet.java:1781)
    at com.microsoft.sqlserver.jdbc.SQLServerResultSet.next(SQLServerResultSet.java:1034)
    at org.apache.commons.dbcp2.DelegatingResultSet.next(DelegatingResultSet.java:191)
    at org.apache.commons.dbcp2.DelegatingResultSet.next(DelegatingResultSet.java:191)
    at org.hibernate.loader.Loader.processResultSet(Loader.java:986)
    at org.hibernate.loader.Loader.doQuery(Loader.java:948)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:340)
    at org.hibernate.loader.Loader.doList(Loader.java:2689)

这显然是由于查询的效率低下,其执行的次数以及处理的行数引起的。


让我们解释一下查询的作用。以下示例:

我有关于超级驱动程序的数据。每行是一个驱动器驱动器,其中包含日期(月),驱动器名称,驱动器可用的座位,起始位置和结束位置。

E。 g。:

Date        Name    Seats       Start   End
-------------------------------------------
7/1/2019    John    45          A       B

每月汇总数据。因此JohnAB之间有9个驱动器,每次他有5个席位。当然,也有其他人沿着相同的路线行驶,因此构成对John的竞争。

Date        Name    Seats       Start   End
-------------------------------------------
7/1/2019    John    45          A       B
7/1/2019    Doe     25          A       A
7/1/2019    Alice   35          A       C
7/1/2019    John    30          A       A
7/1/2019    Doe     25          A       C
7/1/2019    Alice   10          A       B
7/1/2019    Doe     5           A       B
7/1/2019    Alice   15          A       A

因此,对于7/1/2019 John的“网络”(所有路线)进行了以下竞争:

Date        Name    Seats   Route
---------------------------------
7/1/2019    John    30      A-A
7/1/2019    Doe     25      A-A
7/1/2019    Alice   15      A-A

7/1/2019    John    45      A-B
7/1/2019    Doe     5       A-B
7/1/2019    Alice   10      A-B

如您所见,在此结果中,未列出路由A-C,因为John根本没有驱动它。如果将示例数据扩展到新的8/1/2019月份:

Date        Name    Seats       Start   End
-------------------------------------------
8/1/2019    John    65          A       C
8/1/2019    Doe     25          A       A
8/1/2019    Alice   35          A       A
8/1/2019    Doe     25          A       B
8/1/2019    Alice   10          A       B
8/1/2019    Doe     5           A       C
8/1/2019    Alice   15          A       C

我们可以看到John这个月只开车A-C。由于network应该在过去的一年(从2018年8月1日到2019年8月1日)之间建立,因此John的网络现在是所有三个路由({{1} },A-AA-B),但仅用于计算A-C起的竞争对手。对于8/1/20197/1/2019的网络保持JohnA-A。因此,A-B的结果是:

8/1/2019

Date Name Seats Route --------------------------------- 8/1/2019 John 0 A-A 8/1/2019 Doe 25 A-A 8/1/2019 Alice 35 A-A 8/1/2019 John 0 A-B 8/1/2019 Doe 25 A-B 8/1/2019 Alice 10 A-B 8/1/2019 John 65 A-C 8/1/2019 Doe 5 A-C 8/1/2019 Alice 10 A-C 只开车John,这就是为什么他被计为其他路线0席的原因。

由于结果是席位总和而忽略了路线,因此查询的实际输出如下:

A-C

在此结果中,我们只有7/1/2019 John 75 <-- 30+45 7/1/2019 Doe 30 <-- 25+5 7/1/2019 Alice 25 <-- 10+15 8/1/2019 John 65 <-- 65+0+0 8/1/2019 Doe 55 <-- 25+25+5 8/1/2019 Alice 55 <-- 35+10+10 7/1/2019A-A个竞争对手的A-B作为路由,因为在此日期之前没有数据。对于John 8/1/2019的网络是JohnA-AA-B,尽管他只开车A-CA-C({ {1}}和8/1/2019A-A中)。

我希望我提供的数据是可以理解的。如果您需要更多说明,请询问,我将尝试进一步解释。


如何更改查询以大大提高性能?

到目前为止,我还没有使用过A-B,因为我必须加入一个子查询,而HQL不允许这样做。


如果您需要更多信息/说明,请随时询问!


编辑:

我知道我也可以发布在codereview.stackexchange.com上,但是我反对这样做,因为如果只对1个名称执行查询,而对更多名称执行失败,则查询本身可以工作。我对7/1/2019的理解是,应该只存在性能改进问题

1 个答案:

答案 0 :(得分:0)

发布问题后不久,我想到了这个查询:

SELECT f.date,
    f.name,
    SUM(f.seats) 
FROM Foo f 
WHERE f.start + f.end IN (  SELECT fh.start + fh.end 
                            FROM Foo fh 
                            WHERE fh.date BETWEEN DATEADD(yy, -1, f.date) 
                                AND f.date 
                                AND fh.name = '<name>') 
    AND f.date >= '2016-01-01' 
GROUP BY f.date,
    f.name 
ORDER BY f.date ASC,
    SUM(f.seats) DESC

如您所见,我几乎删除了WHERE EXISTS子句。我不确定这是正确的做法还是可能导致什么错误,但是至少可以解决手头的错误(磁盘空间不足)。

如果您对我的查询还有其他想法或意见,请随时与我们分享!

相关问题