检索每个产品的最新日期时间

时间:2014-02-20 12:20:31

标签: sql sqlite max full-table-scan

我有一个大约3GB的SQLite3数据库,我试图查询它以便在两个日期之间显示特定产品的最新订单。

以下是用于创建表的查询:

CREATE TABLE "ProductOrders" (
    "ID" INTEGER NOT NULL  UNIQUE,
    "ProductID" INTEGER NOT NULL,
    "AdditionalInfo" TEXT,
    "OrderDateTime" DOUBLE NOT NULL,
    PRIMARY KEY ("ProductID", "OrderDateTime")
)

我在ProductIDOrderDateTime上创建了索引,以确保表格中没有重复项。

我目前用于执行此操作的查询如下:

Select ProductID, AdditionalInfo, OrderDateTime
  From ProductOrders a
  Where a.OrderDateTime = ( Select max(OrderDateTime)
                              From ProductOrders b
                              Where a.ProductID = b.ProductID
                                AND b.OrderDateTime < 40544.5
                                AND b.OrderDateTime > 40539.5
                          )

该查询工作正常并且完全符合我的要求,但它似乎在扫描整个表格以查询查询的“a”部分。我的踪迹如下:

0|0|0|SCAN TABLE ProductOrders AS a
0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 1
1|0|0|SEARCH TABLE ProductOrders AS b USING COVERING INDEX sqlite_autoindex_ProductOrders_2 (ProductID=? AND OrderDateTime>? AND OrderDateTime<?)

运行至少需要2分钟,这是不可能的。我注意到在结构中ProductID显示为主键1而OrderDateTime显示为主键2,这可能是一个原因吗?

1 个答案:

答案 0 :(得分:0)

如果您将其重写为JOIN,我希望您的查询会表现得更好:

SELECT  a.ProductID, a.AdditionalInfo, a.OrderDateTime
FROM    ProductOrders a
        INNER JOIN
        (   SELECT  b.ProductID, MAX(b.OrderDateTime) AS OrderDateTime
            FROM    ProductOrders b
            WHERE   b.OrderDateTime < 40544.5
            AND     b.OrderDateTime > 40539.5
            GROUP BY b.ProductID
        ) b
            ON a.ProductID = b.ProductID
            AND a.OrderDateTime = b.OrderDateTime;

使用相关子查询,对ProductOrders中的每个记录重新评估子查询(这就是您看到全表扫描的原因),而对于JOIN版本,子查询仅计算一次,结果将被重用有必要的。

在这种情况下,因为您的外部查询非常宽(整个表)并且您的子查询要窄得多(按日期过滤),所以如果您的外部查询非常狭窄(即仅预期到返回几行),然后相关的子查询版本会更好,因为当只需要几个结果时,对所有值执行子查询都没有用。