3

我有一个如下所示的查询:

SELECT 
    ROUND(SUM(AGLR      * BlokInsideAreaFactor), 2) AS AGLRSum,
    ROUND(SUM(Vaarsaed  * BlokInsideAreaFactor), 2) AS VaarsaedSum,
    ROUND(SUM(Vintsaed  * BlokInsideAreaFactor), 2) AS VintsaedSum,
    ROUND(SUM(Oliefroe  * BlokInsideAreaFactor), 2) AS OliefroeSum,
    ROUND(SUM(Baelgsaed * BlokInsideAreaFactor), 2) AS BaelgsaedSum
    .... (+ 10 more columns)
FROM
(
    SELECT
        AGLR,         
        Vaarsaed,     
        Vintsaed,     
        Oliefroe,     
        Baelgsaed, 
        .... (+ 10 more columns)
        Round((CASE WHEN bloktema.AREAL > 0 THEN 
        omraade.Geom.STIntersection(bloktema.Geom).STArea() / bloktema.AREAL ELSE 0 END), 2) 
            AS BlokInsideAreaFactor
    FROM [CTtoolsData].dbo.BlokAfgroedeGrp blokAfgroed
    INNER JOIN [CTtoolsTema].dbo.bloktema2012 bloktema
        ON (bloktema.bloknr = blokAfgroed.bloknr)
    INNER JOIN [CTtoolsTema].dbo.Area omraade 
        ON omraade.Geom.STIntersects(bloktema.GEOM) = 1
    where   omraade.Id = 296
            AND blokAfgroed.[Year] = 2012
) AS Q1

我进行嵌套选择的原因是因为我必须先计算“BlokInsideAreaFactor”,然后再将其与外部选择中的其他列值相乘。

我最初的想法是我会以这种方式优化查询,因为“BlokInsideAreaFactor”每行只计算一次,而不是每行十五次(每列一次)。问题是查询变得非常非常慢这样做。查询大约需要 15 分钟,包含大约 4000 行。不幸的是,我们有老化的硬件,并且正在 SQLServer 2012 Express 上运行查询。

我查看了索引,似乎无法进一步优化。为什么看起来像这样的查询会变得如此缓慢,最重要的是有办法优化它吗?

更新:

涉及的表格如下所示:

BlokAfgroedeGrp:

  • 列:Id(主键、身份)、BlokNr、Year、AGLR、Vaarsaed、Vintsaed...等。
  • 索引:在 Id 上聚集,在 BlokNr + Year 上唯一非聚集

Bloktema2012:

  • 列:Id(主键、身份)、BlokNr、Geom(几何)+其他(不重要)
  • 索引:在 Id 上聚集,在 Geom 上空间,非唯一 - 在 Id + BlokNr 上非聚集,非唯一 - 仅在 BlokNr 上非聚集。

区域:

  • 列:Id(主键、身份)、Geom(几何)+其他(不重要)
  • 索引:在 Id 上聚集,在 Geom 上空间

我确保索引上没有任何碎片。

4

2 回答 2

3

在了解了临时表之后,我最近回到了这个问题。我已经能够优化查询:

DECLARE @TempTable TABLE (AGLR float,         
    Vaarsaed float,     
    Vintsaed float,     
    Oliefroe float,     
    Baelgsaed float, 
    BlokInsideAreaFactor float)

INSERT INTO @TempTable (AGLR, Vaarsaed, Vintsaed, Oliefroe, Baelgsaed, BlokInsideAreaFactor)

SELECT
    AGLR,         
    Vaarsaed,     
    Vintsaed,     
    Oliefroe,     
    Baelgsaed,
    Round((CASE WHEN bloktema.AREAL > 0 THEN 
    omraade.Geom.STIntersection(bloktema.Geom).STArea() / bloktema.AREAL ELSE 0 END), 2) 
        AS BlokInsideAreaFactor
FROM [CTtoolsData].dbo.BlokAfgroedeGrp blokAfgroed
INNER JOIN [CTtoolsTema].dbo.bloktema2012 bloktema
    ON (bloktema.bloknr = blokAfgroed.bloknr)
INNER JOIN [CTtoolsTema].dbo.Area omraade 
    ON omraade.Geom.STIntersects(bloktema.GEOM) = 1
where   omraade.Id = 296
        AND blokAfgroed.[Year] = 2012


SELECT 
ROUND(SUM(AGLR      * BlokInsideAreaFactor), 2) AS AGLRSum,
ROUND(SUM(Vaarsaed  * BlokInsideAreaFactor), 2) AS VaarsaedSum,
ROUND(SUM(Vintsaed  * BlokInsideAreaFactor), 2) AS VintsaedSum,
ROUND(SUM(Oliefroe  * BlokInsideAreaFactor), 2) AS OliefroeSum,
ROUND(SUM(Baelgsaed * BlokInsideAreaFactor), 2) AS BaelgsaedSum
FROM @TempTable

...所以现在查询大约需要 11 秒,而不是 15 分钟。

希望它可以帮助别人!

于 2013-03-22T10:52:51.717 回答
1

你为什么不声明一个变量,把你需要的数据集或值放入变量中,然后引用该变量来做所有的计算呢?然后,您只需要找到该值一次。

如果您不想这样做,您可以创建一个CTE(通用表表达式)表,这样您就可以引用并加入该表,而不是在where子句中执行任何操作。

如果您不使用 SQL Server,那么您可以考虑使用临时表。

于 2012-11-13T23:24:59.447 回答