我是SQL的初学者,我想使用SQL从Oracle数据库查询数据。我有一个表空间,它记录了许多汽车的位置。每个记录都有里程和时间。表空间有三列:“发送时间”、“里程”和“平台”。它们分别表示时间、里程(时间戳格式)和汽车的车牌号码。“SENDTIME”列中的值采用日期时间格式。我想知道一辆特定的汽车什么时候没有移动超过30秒和少于300秒。所以我写了一个SQL查询:
WITH gpsinfo_cte AS (
SELECT plateno, sendtime, longitude, latitude, mileage, createdate,
FIRST_VALUE(sendtime) OVER (PARTITION BY plateno, mileage ORDER BY sendtime) AS first_sendtime,
LAST_VALUE(sendtime) OVER (PARTITION BY plateno, mileage ORDER BY sendtime) AS last_sendtime
FROM GPSINFO
WHERE plateno = '京AEW302'
)
SELECT /*+ NO_MERGE(gpsinfo_cte) */ plateno, sendtime, longitude, latitude, mileage, createdate
FROM gpsinfo_cte
WHERE (last_sendtime - first_sendtime) * 24 * 60 *60 < 300
AND (last_sendtime - first_sendtime) * 24 * 60 *60 > 30;
但在oracle数据库中运行速度较慢。根据Web搜索结果,我尝试使用EXPLAIN PLAN语句为查询生成执行计划,并将其存储在名为PLAN_TABLE的表中。下面是输出:
我仍然不知道如何改进性能。有人能帮忙吗?非常感谢!
2条答案
按热度按时间flseospp1#
这可能是最重要的:
假设您有很多(可能是数千,数百万)汽车,并且只要求一个车牌号码,您希望使用索引来访问该特定汽车的表行。你的执行计划表明这并没有发生:
只需在plateno列上创建一个索引,就可以解决您的问题:
至于查询的其余部分,您将不得不处理逻辑以获得正确的结果,但只要您只处理一辆汽车,就不太可能有明显的性能问题。在逻辑方面,如果我理解正确的话,你想知道什么时候位置记录之间有30-300秒的差距,而它们之间没有里程。因此,您需要将一行与相邻行进行比较。使用
LAG
(或LEAD
):注意:如果你只需要一个
plateno
值,就没有必要在PARTITION BY
子句中包含plateno,因为只有一个,所以这是多余的。你当然可以使用PARTITION BY mileage
作为我这里展示的mileage = last_mileage
逻辑的替代,但是mileage很可能有很多不同的值,并且在内部按这么多值分组意味着很多小的(单行)组,这不是很有内存/临时效率。然而,正如我所说,索引是你唯一的严重问题。h43kikqp2#
为了获得最快的结果,您需要预先计算这些值(第一次和最后一次发送时间)。这可以通过以下方式实现:
plateno
的上下文中,它将更快地计算和保存第一次和最后一次所有这些都需要一些开发时间,而且不会很难。
我也可以让你先试着计算
plateno
,然后提取它的细节。在sendtime
的情况下,我们感兴趣的是第一个(最小)和最后一个(最大)值。因此,您可以用途:如果这是工作,你可以在plateno和sendtime上添加索引,以进一步优化它。