歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Oracle不合理的表設結構計導致執行緩慢

Oracle不合理的表設結構計導致執行緩慢

日期:2017/2/28 15:59:12   编辑:Linux教程
收到開發這邊的確認請求,如下三個語句,執行計劃的COST均一樣,但為什麼實際執行效果相差很大(1)的查詢速度很慢,2)和3)都正常)。

    1. 1)
    2. Select *
    3. From (Select *
    4. From V_Question_Head Vquest0_
    5. Where 1 = 1
    6. Order By Vquest0_.State Asc, Vquest0_.Ask_Time Desc) Where Rownum <= 6;
    7. 2)
    8. Select *
    9. From (Select *
    10. From V_Question_Head Vquest0_
    11. Where 1 = 1 And Rownum <= 6
    12. Order By Vquest0_.State Asc, Vquest0_.Ask_Time Desc);
    13. 3)
    14. Select *
    15. From (Select *
    16. From Question_Head Vquest0_
    17. Where 1 = 1
    18. Order By Vquest0_.State Asc, Vquest0_.Ask_Time Desc) Where Rownum <= 6;

看如下執行計劃,顯然2速度快可以理解,因為行數只有6,而1和3為什麼有那麼大的速度差距,要命的是執行計劃看起來沒有差距。

  1. SELECT STATEMENT, GOAL = ALL_ROWS Cost=1710 Cardinality=6 Bytes=27912
  2. COUNT STOPKEY
  3. VIEW Object owner=GAZA Cost=1710 Cardinality=20237 Bytes=94142524
  4. SORT ORDER BY STOPKEY Cost=1710 Cardinality=20237 Bytes=5949678
  5. TABLE ACCESS FULL Object owner=TEST Object name=QUESTION_HEAD Cost=421 Cardinality=20237 Bytes=5949678
  6. SELECT STATEMENT, GOAL = ALL_ROWS Cost=1710 Cardinality=6 Bytes=27912
  7. VIEW Object owner=TEST Cost=1710 Cardinality=6 Bytes=27912
  8. SORT ORDER BY Cost=1710 Cardinality=6 Bytes=1764
  9. COUNT STOPKEY
  10. TABLE ACCESS FULL Object owner=TEST Object name=QUESTION_HEAD Cost=421 Cardinality=20237 Bytes=5949678
  11. SELECT STATEMENT, GOAL = ALL_ROWS Cost=1710 Cardinality=6 Bytes=28590
  12. COUNT STOPKEY
  13. VIEW Object owner=TEST Cost=1710 Cardinality=20237 Bytes=96429305
  14. SORT ORDER BY STOPKEY Cost=1710 Cardinality=20237 Bytes=5949678
  15. TABLE ACCESS FULL Object owner=TEST Object name=QUESTION_HEAD Cost=421 Cardinality=20237 Bytes=5949678

初步看看,無非1是查視圖,3是直接查表的區別,但關鍵是去掉Order By Vquest0_.State Asc, Vquest0_.Ask_Time Desc後兩者的執行時間差不多,而加上排序後時間就有數十倍的差距,再來看看視圖V_Question_Head

  1. create or replace view v_question_head as
  2. Select t.Accept_Id, t.Industry_Id, t.Dept_Id, t.Title, t.Question, t.Requester, t.Requester_Name, t.Ask_Time, t.Answer,
  3. t.Answer_Man, t.Answer_Time, t.Is_Hot, t.Check_Man, t.Check_Time, t.Satisfaction, t.Satis_Reason, t.Telphone,
  4. t.Is_Display, t.Hot_Sort, t.Check_State, t.State, t.Bbs_Id, t.Acceptor, t.Accept_Time, t.Is_Anonymous,
  5. t.Anonymous_Email, t.Ip_Address, t.Is_Requester_Read,
  6. (Select Count(r1.Accept_Id) From Answer_Remind r1 Where t.Accept_Id = r1.Accept_Id) As Reminded_Count,
  7. (Select (Case
  8. When Count(r2.Accept_Id) > 0 Then
  9. 1
  10. Else
  11. 0
  12. End)
  13. From Answer_Remind r2
  14. Where t.Accept_Id = r2.Accept_Id) As Is_Reminded
  15. From Question_Head t
  16. Order By t.State Asc, t.Ask_Time Desc

通過如上視圖,我們不難發現雖然執行計劃中沒有體現COUNT的代價,但其中有行級的COUNT,也就是主表有多少行就要COUNT多少次,而這時一個很恐怖的數字。顯然這是表結構設計上的問題。而要優化就是要更改表結構,在主表中及上需要COUNT的字段。

Copyright © Linux教程網 All Rights Reserved