【问题标题】:Oracle SQL - Why this query has full table scan?Oracle SQL - 为什么这个查询有全表扫描?
【发布时间】:2014-08-21 21:47:00
【问题描述】:

我对这个查询有疑问:

选择 * FROM customer_table 分区 (p25062014) WHERE (customer_table.username NOT IN ('user1','user2','user3') 或 customer_table.username 为 NULL ) AND (customer_table.ip NOT IN ('ip1','ip2','ip3') OR customer_table.ip 为空 ) AND ( customer_table."ACCOUNT DEVICE ID" NOT IN ('deviceId1','deviceId2','deviceId3') 或 customer_table。“帐户设备 ID”为 NULL )

即使我已在此表上为这些字段创建索引,我的表上仍有“表访问已满”:

在 customer_table 上创建索引 customer_table_USERNAME (用户名) 在 customer_table 上创建索引 customer_table_DEVICE_ID (“帐户设备 ID”) 在 customer_table 上创建索引 customer_table_IP (知识产权) 计划 SELECT STATEMENT ALL_ROWSCost:2 字节:965 基数:1 2 分区范围单成本:2 字节:965 基数:1 分区 #:1 访问的分区 #21 1 TABLE ACCESS FULL TABLE customer_table 成本:2 字节:965 基数:1 分区 #:2 访问的分区 #21

我该如何解决? 谢谢。

【问题讨论】:

  • 如果您的表只有一行(“Cardinality = 1”),那么对于我能想到的几乎所有查询,全表扫描是访问数据的最有效方法。
  • 嗨,Gordon,这个表现在几乎是空的,但很快它将包含每个分区大约 200 万条记录。
  • 需要修复吗?您面临什么实际问题? Null 值没有被索引,not in 通常不能有效地使用索引,因此可能适合进行全表(或分区)扫描 - 即使您确实有不止一行。你的统计数据是最新的吗? Oracle 会根据统计信息和解析查询时认为表所处的状态来选择计划;不是你的预期增长,它对此一无所知。
  • @Fabio 。 . .当您向表中添加更多数据并确保更新了统计信息时,Oracle 将选择更好的执行计划。
  • 我如何确定 Oracle 会更新统计信息?我也可以更改查询以获得更好的性能,但我无法想象不同的查询

标签: sql oracle sql-execution-plan


【解决方案1】:

NOT IN where 子句通常不使用索引,因为从索引中没有什么好处。阅读详情here。尽管该博客解释了为什么在“不等于”比较中忽略索引,但同样适用于 NOT IN

【讨论】:

  • 我如何确定 Oracle 会更新统计信息?我也可以更改查询以获得更好的性能,但我无法想象不同的查询
  • dbms_stat.gather_table_stats 可用于使统计信息保持最新(请参阅 dba-oracle.com/t_dbms_stats_gather_table_stats.htm ),但这不会使索引更有用。可能您能做的最好的事情是减少选择中的列列表(如果您不需要该数据,则不是 SELECT *)并创建一个包含选择列表中的所有列和 where 子句中使用的所有列的生成索引.这使 Oracle 可以进行全索引扫描而不是全表扫描,并且速度可以显着提高。
  • 好的,我将指定列列表而不是
    SELECT *
    但我如何创建包含选择列表中的所有列和使用的所有列的
    生成索引在 where 子句中
    ? where 子句已经存在,选择列表是
    TIMESTAMP, CHANNEL, TDE, MESSAGE, SERVICE ,OFFER
  • 如果您的查询是select a,b,c from mytable where d not in (1,2) and e not in (3,4),则索引将为create index i_mytable on mytable(d,e,a,b,c),因此它可用于检查 where 条件和收集结果(因此 Oracle 不必读取表) .在此示例中,列的顺序可能没有太大区别,因为无论列的顺序如何,全索引扫描都是全索引扫描。但不要将表中的所有列都包含在索引中,否则会失去它的用处!
  • 谢谢,我正在改进我的查询!但我不明白为什么这个查询是全表扫描:
    UPDATE relation_customer SET "OUTPUT SISTEM" = '', "ELAB TIME" = '' WHERE KEY1 = '' AND KEY2 = '' AND KEY3 = '' CREATE INDEX usertalend.INDEX_QUERY_15 ON relation_customer ("OUTPUT SISTEM", "ELAB TIME", KEY1, KEY2, KEY3" );
    我已经看到如果我不包含数字字段“ELAB TIME”在 db 上,访问不在全表扫描中,而如果我包含此字段,则它已满。
猜你喜欢
  • 1970-01-01
  • 2021-01-31
  • 2016-08-14
  • 1970-01-01
  • 2021-11-08
  • 2011-02-16
  • 1970-01-01
  • 2020-03-19
  • 1970-01-01
相关资源
最近更新 更多