HQL查询导致磁盘不足space异常

HQL query causing insufficient disk space exception

我有以下 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)

这显然是由于查询效率低下及其执行次数和处理的行数造成的。


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

我有优步 driver 的数据。每行是 driver 的一个驱动器,带有日期(月)、driver 名称、driver 可用的座位、开始位置和结束位置。

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 Johns "network" (所有路线) 有这个比赛:

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 应该建立在过去一年的时间跨度(8/1/2018 到 8/1/2019),Johns 网络现在是所有三个路线(A-A, A-B, A-C), 但仅用于计算截至 8/1/2019 的竞争对手。对于 7/1/2019Johns 网络保持 A-AA-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只开过A-C,这就是为什么他被算作其他路线的0个座位的原因。

由于结果是对座位求和而忽略了路线,所以查询的实际输出如下:

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/2019 的路线作为 A-AA-BJohn 竞争对手的路线,因为在该日期之前没有数据。对于 8/1/2019 John 的网络是 A-AA-BA-C,即使他只在 8/1/2019 开车 A-CA-AA-B7/1/2019 中)。

我希望我提供的数据是可以理解的。如果您需要更多说明,请直接提问,我会尽力解释更多。


我需要如何更改查询才能大大提高性能?

到目前为止我还没有使用 JOINs,因为我必须加入子查询,而这在 HQL 中是不允许的。


如果您需要更多info/clarification,请随时询问!


编辑:

我知道我也可以在 codereview.stackexchange.com 上发帖,但我选择了反对,因为查询本身是有效的,如果只对 1 个名称执行并且只对更多名称执行失败。我对codereview.stackexchange.com的理解是,应该只有性能提升问题

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

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 子句。我不太确定这样做是否正确,或者这可能导致什么错误,但它至少解决了手头的错误(磁盘不足 space 异常)。

如果您对我的查询有其他想法或评论,请随时分享!