【问题标题】:Why does the same select statement have different costs in Oracle?为什么相同的select语句在Oracle中有不同的成本?
【发布时间】:2015-05-27 14:02:28
【问题描述】:

最近我使用Oracle 11g 数据库做作业。我有 12 个表,例如 trip_data_11 和 trip_data_12。 它们具有相同的结构并且记录的数量几乎相同。我在每个表上创建了相同的索引。 所以对于trip_data_11表:

create index pick_add_11 on trip_data_11(pickup_longitude,pickup_latitude);
create index drop_add_11 on trip_data_11(dropoff_longitude,dropoff_latitude);

对trip_data_12进行同样的操作。

然后我使用下面的 select 语句来选择每天的出租车号码。

SELECT
   COUNT(DISTINCT(td.medallion)) AS taxi_num
FROM
   SYS.TRIP_DATA_11 td
WHERE 
    (td.pickup_longitude >= -74.2593 AND td.pickup_longitude <= -73.7011
     AND td.pickup_latitude >= 40.4770 AND td.pickup_latitude <= 40.9171
    )
    AND
    (td.dropoff_longitude >= -74.2593 AND td.dropoff_longitude <=    -73.7011
    AND td.dropoff_latitude >= 40.4770 AND td.dropoff_latitude <=  40.9171
  )
 AND
     td.trip_distance > 0
 AND
     td.passenger_count > 0
  GROUP BY 
      regexp_substr(td.pickup_datetime,'\d{4}-\d{2}-\d{2}')
  ORDER BY
      regexp_substr(td.pickup_datetime,'\d{4}-\d{2}-\d{2}');

耗时38sec。当我将表名改为SYS.TRIP_DATA_12时,问题来了,耗时2个多小时。 更重要的是,它并没有结束。我不知道为什么。

今天我问我的同学,他说:清除缓存。所以我用下面的语句来做。

alter system flush shared_pool;
alter system flush buffer_cache;
alter system flush global context;

现在,当我对 SYS.TRIP_DATA_11 使用相同的选择语句时,我得到的性能与 SYS.TRIP_DATA_12 一样差。为什么?

【问题讨论】:

  • 首先,永远不要在 SYS 模式中创建对象。 SYS 的行为与其他模式不同。不知道这是否是一个问题,但它无济于事。桌子有多大?表和索引的统计信息是否准确且最新?
  • 感谢您的建议。但是我创建的所有表都使用 sys 帐户。这些表包含几乎 14,000,000。昨天,我创建了表并使用 Ttoad 加载数据,然后创建了索引。所以表和索引的统计数据是准确和最新的。
  • 如果您打算使用SYS 帐户,预计您可能会遇到看起来像错误的奇怪行为。您在此过程的哪个阶段收集了统计数据?
  • 刚刚获得一个月每天的出租车数量。

标签: oracle performance query-optimization


【解决方案1】:

看来你的同学在拿你开玩笑。

很明显,您的查询之所以表现良好,是因为您有一个温暖的缓冲区缓存,其中包含您需要从 TRIP_DATA_11 获得的所有数据。通过刷新缓存,你已经消除了所有这些,现在所有表的性能都一样差。

调优查询很困难,因为有很多可能性。 Please read the documentation on it.

只选择一件事:您正在搜索范围,这是有问题的。填充了多少行 -74.2593 to -73.7011 ?它可能比-71.00 to -68.59 说的要多得多,尽管范围更广。了解您的数据——它的数量、分布和偏差——是至关重要的。

作为第一步,学习如何使用 EXPLAIN PLAN。 Find out more。要获得更好的计划,请使用 DBMS_STATS 包收集有关表及其索引的统计信息。 Find out more.

一个提示。 Oracle 只使用一个索引来访问一张表。所以它会选择pick_add_11 drop_add_11,但不会同时选择两者。然后它将从表中读取所有匹配的记录并按其他条件过滤它们。您可能会从设计用于服务此查询的索引中获得更好的性能:

create  index add_11 on trip_data_11
   (pickup_longitude
    , pickup_latitude
    , dropoff_longitude
    , dropoff_latitude
    , trip_distance 
    , passenger_count )
;

select 语句将针对该索引执行整个过滤器,并且仅触摸表以获取 MEDALLION 值。 (您也可以将medallion 添加到索引中)。试验列顺序。由于纬度的范围比经度的范围窄,因此可能应该先行;也许下车价值应该出现在接送之前。您需要一个索引,其中最大数量的相关记录聚集在一起。

这样的索引可能会产生开销,因此我们不希望在现实生活中维护太多索引。但它们是调整频繁运行的昂贵查询的一种有价值的技术。


哦,@Justin 说得对:不要使用 SYS 来执行应用程序工作。即使对于学校作业,您也应该创建一个新的架构并在其中创建表等。

【讨论】:

  • 感谢您给我丢失的提示并编辑我的问题。每个表存储为 cvs 格式,大小为 2.5G。我使用 Toad 将数据加载到 db,每个表的记录数几乎为 14,000,000。其次,作业要求经度从-74.2593到-73.7011,纬度从40.9171到40.4770。
  • @APU,我使用 sys 帐户创建了一个用户,并为其创建了 tempspace 和 defaultspace。然后创建了 trip_data_12 表并加载了数据。根据您的提示创建了索引,但是,select 语句成本3小时多,但没有结束。我不知道为什么第一次使用 trip_data_11 的选择语句只需要 38 秒。那个时候db也没有缓存。
  • @yunfeng - 恐怕我无法远距离诊断代码中的性能问题。您必须向老师或知识渊博的同学寻求帮助。
  • @APU,谢谢,我再试试看。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-07
  • 1970-01-01
  • 2023-04-01
  • 1970-01-01
  • 2014-05-02
  • 1970-01-01
相关资源
最近更新 更多