SQL花时间执行

时间:2018-05-09 05:42:51

标签: sql oracle performance query-optimization

Select pinv.pipeline_ref_id  Invoice_No,
 pinv.orig_company_id Company,
 pinv.orig_terminal_id Terminal,
 phwb.pipeline_ref_id HWB_No,
 ih.transport_mode Trans_Mode,
 ih.import_export_ind Business_Type,
 to_date(ms.accounting_date,'dd/mm/yy') BL_Confirm_date,
to_date(sf_get_local(pinv.pipeline_tx_status_date,pinv.status_date_tz_code),'dd/mm/yy') Inv_Void_Date,
 (pinv.pipeline_tx_status_date - ms.accounting_date) BL_Days, ih.billto_name BillTo_Name, ppi.partner_id BillTo_ID,
pinv.last_modified_by Executed_By, ih.oc_invoice_amt Invoice_Amount

From pipeline pinv

JOIN invoice_header ih ON pinv.pipeline_tx_id = ih.pipeline_tx_id
JOIN pipeline_relations prin ON pinv.pipeline_tx_id = prin.pipeline_tx_id 
JOIN pipeline phwb ON prin.rel_pipeline_tx_id = phwb.pipeline_tx_id
JOIN multisegment_status ms ON phwb.pipeline_tx_id = ms.pipeline_tx_id
JOIN pipeline_parties ppi ON ppi.partner_role = 'BT'
Where
(TRUNC(sf_get_local(pinv.pipeline_tx_status_date,pinv.status_date_tz_code)) between to_date('&1','DD-MON-YYYY:HH24:MI:SS') AND to_date('&2','DD-MON-YYYY:HH24:MI:SS'))

我是Oracle的新手。 对于1小时数据获取,SQL需要几个小时。请你检查一下我做错了什么。

还有一件事是如何运作的:

TRUNC(sf_get_local(pinv.pipeline_tx_status_date,pinv.status_date_tz_code)) between to_date('&1','DD-MON-YYYY:HH24:MI:SS') AND to_date('&2','DD-MON-YYYY:HH24:MI:SS')

谢谢, fuko

2 个答案:

答案 0 :(得分:3)

  

究竟是如何运作的

sf_get_local()是应用程序中的一个函数,而不是Oracle内置的函数,因此您可以查看其来源以确定它的作用,但我们不能。但是,我猜它会将UTC中的时间戳转换为本地时区。 trunc()删除了时间元素,因此2018-05-08 15:20:01.542将变为2018-05-08,这似乎有点奇怪,因为操作数以日期时间格式表示为秒。

至于为什么“SQL花费数小时”,我们很难说。性能诊断需要更多细节。解释计划会有所帮助。 Find out more.

明显的事情要看:

WHERE子句可能不使用索引(除非你在pipeline(trunc(sf_get_local(pipeline_tx_status_date,status_date_tz_code))上有一个基于函数的索引。问题是你是在过滤日期因此,优化器很难判断使用索引是一件好事。如果范围是一小时而你正在扫描五年的数据,那么索引是有用的。但是如果范围跨越一年并且你不是有五年的数据。

您正在查看一小时的数据,因此您可能会从构建基于函数的索引中获得一些好处。 Find out more

此联接实际上是一个CROSS JOIN

JOIN pipeline_parties ppi ON ppi.partner_role = 'BT'

您不会通过标识符将pipeline_parties加入查询中的任何其他表。这意味着您的结果集将是pipeline_partiespartner_role = 'BT'所有行中所有其他行的乘积。也许这只是一行,在这种情况下你应该明确关于CROSS JOIN。否则,返回的数据超出了您的需要可能是查询需要时间的另一个原因。

您的某些联接看起来像这样

JOIN multisegment_status ms ON phwb.pipeline_tx_id = ms.pipeline_tx_id

但是一切都来自pipeline。您可以通过将所有子表连接到该表来帮助优化器做出更明智的决策:

JOIN multisegment_status ms ON pinv.pipeline_tx_id = ms.pipeline_tx_id

请注意,您再次在此处生成产品。除非所有其他表与pipeline具有一对一的关系,否则您将生成所有选定记录的排列。可能这不是你想要的。

此时我们必须指出这是您的数据模型和业务规则。您需要了解您正在实施的逻辑以及数据如何符合该逻辑。这意味着您需要了解数据模型中表之间的关系。

答案 1 :(得分:0)

假设您已准备好索引来帮助JOIN s,那么下一个最好看的地方就是WHERE子句。

理想情况下,您不应将搜索列放在函数中。将搜索列放在函数中可防止其索引被有效使用。 (在网上搜索SARGable。)例如,如果您有合适的索引,此处的第一个代码段可以比第二个代码段运行得快......

WHERE
       myTable.dateColumn >= TRUNC(to_date('&1','DD-MON-YYYY:HH24:MI:SS'))
   AND myTable.dateColumn <  TRUNC(to_date('&2','DD-MON-YYYY:HH24:MI:SS')) + INTERVAL '1' DAY

Vs

WHERE
  TRUNC(myTable.dateColumn) BETWEEN to_date('&1','DD-MON-YYYY:HH24:MI:SS')
                                AND to_date('&2','DD-MON-YYYY:HH24:MI:SS')

仍然留下函数调用:

sf_get_local(pinv.pipeline_tx_status_date,pinv.status_date_tz_code)

您应该在其上放置一个基于函数的索引,以便可以对函数调用的结果建立索引。

然后你需要开始查看解释计划。确定计划的哪一部分是最昂贵的,并解决这些特定部分。 (如果你在你的问题中包含解释计划,它甚至会有所帮助。)