Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/83.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 从自定义队列中选择下一条消息时性能低下_Sql_Oracle_Sorting_Queue_Indexing - Fatal编程技术网

Sql 从自定义队列中选择下一条消息时性能低下

Sql 从自定义队列中选择下一条消息时性能低下,sql,oracle,sorting,queue,indexing,Sql,Oracle,Sorting,Queue,Indexing,我有一个简单的基于表的队列系统。在最简单的形式中,它由id、队列名称和状态组成。当从给定队列读取下一条消息时,我们需要确保FIFO(先进先出),即给定队列中具有给定状态的最低id。这一切都适用于大约1000行,但当我们达到1M+行时,情况就不太好了 我们不能使用rownum=1,因为这是在排序之前完成的,排序仅基于id列(asc)完成。如果我制作一个游标并按id排序1000次,总共需要大约100毫秒,这是一个很好的性能(0.1毫秒/循环)。如果我在查询中包含状态和队列名称(我需要它,因为我需要特

我有一个简单的基于表的队列系统。在最简单的形式中,它由id、队列名称和状态组成。当从给定队列读取下一条消息时,我们需要确保FIFO(先进先出),即给定队列中具有给定状态的最低id。这一切都适用于大约1000行,但当我们达到1M+行时,情况就不太好了

我们不能使用rownum=1,因为这是在排序之前完成的,排序仅基于id列(asc)完成。如果我制作一个游标并按id排序1000次,总共需要大约100毫秒,这是一个很好的性能(0.1毫秒/循环)。如果我在查询中包含状态和队列名称(我需要它,因为我需要特定队列的未读消息的最低id),那么10个循环(130ms/loop)大约需要1300ms,这远远不够

我尝试在这三列中的每一列上都有一个索引,还有一个关于id、队列、状态的组合索引,最后是一个关于id的组合索引,以及一个关于队列和状态的组合索引。id列也是主键。所有组合都已在基于规则的设置中尝试过(使用规则提示)

致以最良好的祝愿, Michael Ringholm Sundgaard-iHedge A/S www.ihedge.dk www.ibrain.dk

总体思路是:

select id from
(select id
   from queue_table
   where queue_name = 'nameOfQueue'
   and processed = 'NO'
   order by id
)
where rownum = 1

您是否考虑过使用Oracle AQ来实现此目的,而不是使用您自己的?

您尝试的索引中没有提到的一件事是索引(队列、状态、id)。如果你把id放在索引的开头,它会破坏索引的使用,因为你在寻找“最低的一个”,这在应用其他标准之前是没有意义的


索引中列的顺序通常与实际列本身一样重要。

我猜您的索引没有被使用,因为尚未为索引收集统计数据


退房。您可以在查询中提供提示,强制使用您创建的索引。如果这有帮助,那么为您的表运行DBMS_STATS.gather_table_STATS包将强制更新统计信息,从而消除对提示的需要。最终数据库将

您还没有向我们共享查询。与排序1M行相比,排序几千行更容易。可能还有很多其他原因需要检查性能?检查以下各项:

  • 你的桌子被分析了吗?是否使用了
    DBMS\u STATS.gather\u table\u STATS
    gather\u index\u STATS
  • 你检查过计划了吗?它们是否显示所使用的索引
  • 您的Oracle是什么版本

你应该按照建议去尝试。

一些丑陋/聪明的黑客可能会奏效,也可能是技术过度

1) 您可以像这样创建一个很好的基于函数的索引(语法可能有点错误,现在还没有访问Oracle的权限)

然后您可以这样选择:

  SELECT --+ index_asc(q my_small_queue_index)
     decode(is_processed,'YES',null,id) AS id
  FROM queue_table q
  WHERE decode(is_processed,'YES',null,queue_name) = 'some queue name'
    AND rownum = 1;
如果有很大比例的已处理行,而只有很少的未处理行(10^9,而只有几百行),那么应该可以很好地工作。在任何情况下都不应该超过几次


2) 如果队列名称是固定的,并且数量不多,则可以为每个队列创建分区。

重新通知使用索引提示(无order by),即

选择--+索引\u asc(q my\u small\u queue\u index) 将(正在处理,'YES',null,id)解码为id 从队列_表q 其中decode(正在处理,'YES',null,队列名称)='some queue name' rownum=1


这是非常危险的。如果该索引被删除、重命名、设置为不可用,或者优化器选择快速完全扫描,那么您不会得到任何错误,您仍然会返回1行,但不能保证它是正确的行。使用索引是可以的,但是您仍然必须有ORDERBY子句来保证正确的结果

你能给我们看一下询问和解释计划吗。是的,我们在敏捷ESB iBrain中也支持AQ,但是我们需要一个更简单甚至更快的AQ版本。从这个意义上讲,我们还需要通用性,我们可以在所有主要数据库上实现我们的队列系统IQ,并使它们的行为类似于我们所做的。--创建表创建表IBRAIN\U queue\U FARM(队列名称VARCHAR2(50)不为空,消息ID号不为空,状态VARCHAR2(20)不为空,上次操作时间日期不为空,消息数据NCLOB不为空,相关性ID VARCHAR2(200))更改表IBRAIN_队列_场添加约束PK_IQF_消息_ID主键(消息_ID)在IBRAIN_队列_场上创建索引IBRAIN_Q_F_INDX01(队列名称、状态、消息_ID)--查询选择IQF_outer.MESSAGE_数据,iqf_outer.message_id,iqf_outer.correlation_id from ibrain_queue_farm iqf outer,(从ibrain_queue_farm iqf中选择min(iqf.message_id)message_id,其中iqf.queue_name=p_queue_name,iqf.status='NEW'),iqf_inner其中iqf_outer.message_id=iqf_inner.message_id;您应该编辑原始帖子,并在其中添加表和查询信息,以供将来参考。即使在查询完成后进行必要的更新,并使用表锁定,它现在每个循环的执行速度为0.45毫秒(半毫秒),非常好,谢谢大家。在复合索引中,列顺序似乎被忽略了很多。
  SELECT --+ index_asc(q my_small_queue_index)
     decode(is_processed,'YES',null,id) AS id
  FROM queue_table q
  WHERE decode(is_processed,'YES',null,queue_name) = 'some queue name'
    AND rownum = 1;