在不创建索引的情况下,我可以做些什么来提高oracle查询的查询性能?
以下是我试图更快地运行的查询:
SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a,
itempages b,
keygroupdata c
WHERE a.ItemType IN (112,115,189,241)
AND a.ItemNum = b.ItemNum
AND b.ItemNum = c.ItemNum
ORDER BY a.DateStored DESC
这些列都没有编入索引,每个表都包含数百万条记录。不用说,查询执行需要3分半钟。这是生产环境中的第三方数据库,我不允许创建任何索引,因此必须对查询本身进行任何性能改进。
谢谢!
答案 0 :(得分:8)
要求第三方为其连接列编制索引,因为它们应该首先完成!如果没有索引,甲骨文除了蛮力之外别无他法。
答案 1 :(得分:7)
首先,我将查询重写为ANSI标准:
SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a
INNER JOIN itempages b ON b.ItemNum = a.ItemNum
INNER JOIN keygroupdata c ON c.ItemNum = b.ItemNum
WHERE a.ItemType IN (112,115,189,241)
ORDER BY a.DateStored DESC
这使得阅读和理解正在发生的事情变得更加容易。它还可以帮助您避免错误(即交叉加入),这可能会导致真正的大问题。然后我会得到解释计划,看看DBMS正在对该查询做些什么。它试图使用一些索引吗?是否正确加入了表格?
然后我会查看我正在使用的表,看看是否有任何已存在的索引可用于更快地查询。最后,正如其他人一样,我建议我删除Order By子句,然后在代码中执行此操作。
答案 2 :(得分:6)
您可能想尝试在任何这些表上创建物化视图。然后,您可以在物化视图上创建一个索引,以帮助加快查询速度(然后查询物化视图而不是原始表)。
当然,如果您的基础表已更新,则需要刷新视图和索引。
答案 3 :(得分:3)
首先,看一下执行计划。它是否准确反映了在查询执行的每个阶段要检索的行数?谓词“a.ItemType IN(112,115,189,241)”的选择性如何?执行计划是否显示临时磁盘空间用于连接或排序?
实际上,也许您可以修改问题以包含执行计划。
还要确保没有禁用散列连接,这在OLTP调优系统中有时也是如此,因为它们是在Oracle中等效批量数据的最有效方式。他们应该出现在执行计划中。
答案 4 :(得分:3)
您可以在加入表格之前尝试过滤项目类型,如下所示。
如果您在9i之前运行Oracle,这有时会带来惊人的好处。
select
c.claimnumber,
a.itemdate,
c.dtn,
b.filepath
from
(
select itemdate
from items it
where it.itemtype in(112,115,189,241)
) a
itempages b,
keygroupdata c
where a.itemnum = b.itemnum
and b.itemnum = c.itemnum
你也可以尝试添加提示/ + RULE /或/ + ORDERED /来看看会发生什么......再次,特别是对于旧版本,这些有时会给出了令人惊讶的结果。
SELECT /*+RULE*/
c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM
items a,
itempages b,
keygroupdata c
WHERE a.ItemType IN (112,115,189,241)
AND a.ItemNum = b.ItemNum
AND b.ItemNum = c.ItemNum
ORDER BY a.DateStored DESC
答案 5 :(得分:1)
如果查询输入是常量或可预测的(itemType IN (...)
),那么另一种方法是每天运行一次或两次查询并将结果存储在本地表中,并在适当的情况下使用索引。
然后,您可以使代价高昂的查询“离线”,并为交互式查询提供更快/更好的结果。
答案 6 :(得分:1)
这是您经常运行的查询吗?似乎数据库所有者有兴趣创建加速此查询所需的索引。运行查询的3.5分钟必须对其生产环境产生一些影响!
另外,他们是否一直在运行表的更新统计信息?这可能会提高性能,因为连接顺序是根据表的统计信息计算的。
顺便说一下,你有什么可以做的?刚读过?如果您可以创建临时表并在其上放置索引,我可以考虑制作表的临时副本,索引这些表,然后使用临时副本执行索引辅助连接。答案 7 :(得分:1)
我知道这个帖子已经很老了,但对于搜索引擎,我仍然想提供一个可以在oracle上运行的替代解决方案,并且根据数据可能要快得多。
with a as (
select
*
from
items
where
ItemType IN (112,115,189,241)
)
SELECT
c.ClaimNumber
, a.ItemDate
, c.DTN, b.FilePath
FROM
a,
itempages b,
keygroupdata c
WHERE
a.ItemNum = b.ItemNum
AND b.ItemNum = c.ItemNum
ORDER BY
a.DateStored DESC
您还可以尝试/*+ MATERIALIZE */
子句中的WITH
提示。
实际上我发现oracle的旧连接语法比ansi sql ^^
更容易阅读答案 8 :(得分:0)
如果没有索引,那么随着表格大小的增加,该查询只会变得更糟。 话虽如此,尝试删除order by子句并在客户端进行那种排序。
答案 9 :(得分:0)
是否收集了这些表格的统计数据?如果没有,收集统计数据可能会改变执行计划,尽管它不一定会好起来。
除此之外,请查看执行计划。您可能会看到它以非最佳顺序连接表(例如,它可能在加入具有过滤条件的a之前加入b和c)。
您可以使用提示尝试影响访问路径,连接顺序或连接方法。
更新:对评论的回应促使我进行了this演示,这可能会有所帮助,或者至少是有趣的。
答案 10 :(得分:0)
有时,您可以通过为优化器添加额外的路径来看到好处,通过向where子句添加看似多余的元素来进行选择。
例如,你有A.ItemNum = B.ItemNum AND B.ItemNum = C.ItemNum。尝试添加A.ItemNum = C.ItemNum。但是,我很确定优化器足够聪明,可以自己解决这个问题 - 值得一试。
答案 11 :(得分:0)
根据ItemType列的数据类型,如果它是varchar,使用以下内容可能会更快执行,Oracle将会进行转换。
SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a,
itempages b,
keygroupdata c
WHERE ((a.ItemType IN ('112','115','189','241'))
AND (a.ItemNum = b.ItemNum)
AND (b.ItemNum = c.ItemNum))
ORDER BY a.DateStored DESC
答案 12 :(得分:0)
如果你说没有索引,那么这是否也意味着没有定义主键或外键?显然,分析表和收集统计信息很重要,但是如果不存在诸如定义表应该如何连接的元数据,则Oracle可能会选择较差的执行路径。
在这种情况下,使用诸如/ * + ORDERED * /之类的提示可能是使优化器可靠地选择良好执行路径的唯一选择。也可能值得添加外键和主键,但将它们定义为DISABLE和VALIDATE。
我想这篇评论的用处取决于对索引的厌恶程度如何,YMMV。
答案 13 :(得分:0)
首先在此查询上创建一个视图,然后从该视图生成一个表。还可以在日期创建索引,创建作业并在系统空闲时的午夜时间安排它。
答案 14 :(得分:0)
好吧,既然你不能创建索引,我会确保统计数据都是最新的,我会用这种方式重写查询:
with a as (select /*+ MATERIALIZE */ ItemType, ItemNum, DateStored, ItemDate from items where ItemType in (112,115,189,241))
SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM a,
itempages b,
keygroupdata c
WHERE a.ItemNum = b.ItemNum
AND b.ItemNum = c.ItemNum
ORDER BY a.DateStored DESC
答案 15 :(得分:-1)
删除ORDER BY
在将行拉回应用程序后执行排序。