Oracle里count(1)、count(*)和count(主键)哪个更快

前端之家收集整理的这篇文章主要介绍了Oracle里count(1)、count(*)和count(主键)哪个更快前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

这两天听了将近20场演讲,感觉收获很多,最深的感觉就是自己还有很长的路要走。有几个点记录一下:

昨天听老猫讲,提到一个普遍的问题就是Oracle里count(*)、count(1)和count(主键)到底哪个快的问题。这个问题看起来很简单,每个人都会有自己的答案,去百度上搜会出来一大堆帖子来讲哪个更快。但是老猫说了它们三个其实是一样的,我听到之后也觉得挺诧异的,因为我记得别人跟我说过count(主键)会快,然后自己简单想了一下,觉得好像是那么回事的就没有深入去追究。接着老猫说官方有这样的说法这三个其实是等价的。晚上回来之后到MOS上查了一下,居然被我找到了How the Oracle CBO Chooses a Path for the SELECT COUNT(*) Command (文档 ID 124717.1)。这篇文档讲的就是在CBO优化器模式下,Oracle怎样去评估没有where条件select count(*)和select count(colum)语句的最优路径。

1、创建测试表并设计测试场景:

  1. --创建测试表
  2. sys@ORCL>createtablejournal_entries
  3. 2(id_jenumber(8),3date_jedatenotnull,4balancednumber,5constraintindx_ecr_id_jeprimarykey(id_je)
  4. 6);
  5.  
  6. Tablecreated.
  7. --创建索引
  8. sys@ORCL>createindexindx_ecr_date_je_balancedonjournal_entries(date_je,balanced);
  9.  
  10. Indexcreated.
  11.  
  12. sys@ORCL>createindexindx_ecr_balanced_date_jeonjournal_entries(balanced,date_je);
  13.  
  14. Indexcreated.
  15.  
  16. sys@ORCL>createindexindx_ecr_balancedonjournal_entries(balanced);
  17.  
  18. Indexcreated.
  19. --插入测试数据
  20. sys@ORCL>insertintojournal_entriesvalues(1,sysdate,11);
  21.  
  22. 1rowcreated.
  23.  
  24. sys@ORCL>insertintojournal_entriesvalues(2,21);
  25.  
  26. 1rowcreated.
  27.  
  28. sys@ORCL>insertintojournal_entriesvalues(3,31);
  29.  
  30. 1rowcreated.
  31.  
  32. sys@ORCL>insertintojournal_entriesvalues(4,41);
  33.  
  34. 1rowcreated.
  35.  
  36. sys@ORCL>insertintojournal_entriesvalues(5,51);
  37.  
  38. 1rowcreated.
  39.  
  40. sys@ORCL>insertintojournal_entriesvalues(6,61);
  41.  
  42. 1rowcreated.
  43.  
  44. sys@ORCL>insertintojournal_entriesvalues(7,71);
  45.  
  46. 1rowcreated.
  47.  
  48. sys@ORCL>insertintojournal_entriesvalues(8,81);
  49.  
  50. 1rowcreated.
  51.  
  52. sys@ORCL>insertintojournal_entriesvalues(9,91);
  53.  
  54. 1rowcreated.
  55.  
  56. sys@ORCL>commit;
  57.  
  58. Commitcomplete.
  59. --收集统计信息
  60. sys@ORCL>execdbms_stats.gather_table_stats(ownname=>USER,tabname=>'JOURNAL_ENTRIES',cascade=>true);
  61.  
  62. PL/sqlproceduresuccessfullycompleted.

设计四个场景进行对比:

Sel1 : Select count(*) from journal_entries;
Sel2 : Select count(1) from journal_entries;
Sel3 : Select count(id_je) from journal_entries;

Sel4 : Select count(balanced) from journal_entries;

1、场景1和场景2等价

For CBO,Sel1 and Sel2 are strictly equivalent

  1. sys@ORCL>altersessionsetstatistics_level=all;
  2.  
  3. Sessionaltered.
  4.  
  5. sys@ORCL>selectcount(*)fromjournal_entries;
  6.  
  7. COUNT(*)
  8. ----------
  9. 9
  10.  
  11. sys@ORCL>select*fromtable(dbms_xplan.display_cursor(null,null,'runstats_last'));
  12.  
  13. PLAN_TABLE_OUTPUT
  14. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  15. sql_ID5ja3ukp4wd73p,childnumber0
  16. -------------------------------------
  17. selectcount(*)fromjournal_entries
  18.  
  19. Planhashvalue:42135099
  20.  
  21. ---------------------------------------------------------------------------------------------
  22. |Id|Operation|Name|Starts|E-Rows|A-Rows|A-Time|Buffers|
  23. ---------------------------------------------------------------------------------------------
  24. |0|SELECTSTATEMENT||1||1|00:00:00.01|1|
  25. |1|SORTAGGREGATE||1|1|1|00:00:00.01|1|
  26. |2|INDEXFULLSCAN|INDX_ECR_ID_JE|1|9|9|00:00:00.01|1|
  27. ---------------------------------------------------------------------------------------------
  28.  
  29.  
  30. 14rowsselected.
  31.  
  32. sys@ORCL>selectcount(1)fromjournal_entries;
  33.  
  34. COUNT(1)
  35. ----------
  36. 9
  37.  
  38. sys@ORCL>select*fromtable(dbms_xplan.display_cursor(null,'runstats_last'));
  39.  
  40. PLAN_TABLE_OUTPUT
  41. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  42. sql_IDgbxjjuqj9j7ww,childnumber0
  43. -------------------------------------
  44. selectcount(1)fromjournal_entries
  45.  
  46. Planhashvalue:42135099
  47.  
  48. ---------------------------------------------------------------------------------------------
  49. |Id|Operation|Name|Starts|E-Rows|A-Rows|A-Time|Buffers|
  50. ---------------------------------------------------------------------------------------------
  51. |0|SELECTSTATEMENT||1||1|00:00:00.01|1|
  52. |1|SORTAGGREGATE||1|1|1|00:00:00.01|1|
  53. |2|INDEXFULLSCAN|INDX_ECR_ID_JE|1|9|9|00:00:00.01|1|
  54. ---------------------------------------------------------------------------------------------
  55.  
  56.  
  57. 14rowsselected.

可以看到两个语句的执行计划是完全相同的。

2、场景3也与前两个场景等价,因为id_je有NOT NULL约束

For Sel3,CBO does the same as for Sel1 and Sel2 since "id_je" has aNOT NULL constraint.

  1. sys@ORCL>selectcount(id_je)fromjournal_entries;
  2.  
  3. COUNT(ID_JE)
  4. ------------
  5. 9
  6.  
  7. sys@ORCL>select*fromtable(dbms_xplan.display_cursor(null,'runstats_last'));
  8.  
  9. PLAN_TABLE_OUTPUT
  10. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  11. sql_IDb1p4v15dwx7hs,childnumber0
  12. -------------------------------------
  13. selectcount(id_je)fromjournal_entries
  14.  
  15. Planhashvalue:42135099
  16.  
  17. ---------------------------------------------------------------------------------------------
  18. |Id|Operation|Name|Starts|E-Rows|A-Rows|A-Time|Buffers|
  19. ---------------------------------------------------------------------------------------------
  20. |0|SELECTSTATEMENT||1||1|00:00:00.01|1|
  21. |1|SORTAGGREGATE||1|1|1|00:00:00.01|1|
  22. |2|INDEXFULLSCAN|INDX_ECR_ID_JE|1|9|9|00:00:00.01|1|
  23. ---------------------------------------------------------------------------------------------
  24.  
  25.  
  26. 14rowsselected.

可以看到执行计划与前两个也是完全相同的。

4、场景4跟前边3个不同,因为balanced列上没有NOT NULL约束,但是balanced列上有索引,那会走这个列上的索引么?我们来看一下执行计划:

  1. sys@ORCL>selectcount(balanced)fromjournal_entries;
  2.  
  3. COUNT(BALANCED)
  4. ---------------
  5. 9
  6.  
  7. sys@ORCL>select*fromtable(dbms_xplan.display_cursor(null,'runstats_last'));
  8.  
  9. PLAN_TABLE_OUTPUT
  10. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  11. sql_IDbc3bc8c0fg14z,childnumber0
  12. -------------------------------------
  13. selectcount(balanced)fromjournal_entries
  14.  
  15. Planhashvalue:3638043346
  16.  
  17. --------------------------------------------------------------------------------------------------------
  18. |Id|Operation|Name|Starts|E-Rows|A-Rows|A-Time|Buffers|
  19. --------------------------------------------------------------------------------------------------------
  20. |0|SELECTSTATEMENT||1||1|00:00:00.01|1|
  21. |1|SORTAGGREGATE||1|1|1|00:00:00.01|1|
  22. |2|INDEXFULLSCAN|INDX_ECR_DATE_JE_BALANCED|1|9|9|00:00:00.01|1|
  23. --------------------------------------------------------------------------------------------------------
  24.  
  25.  
  26. 14rowsselected.

我们看到这个执行计划没有走balanced列上的索引,而是走了和date_je的联合索引。这个可以查看另一篇文档:Note:67522.1 Why is my index not used?

小结一下:

我这里只是简单的从执行计划上看count(*)、count(1)和count(主键)其实是一致,MOS的文档中详细的讲解了Oracle是如何评估执行计划的,也可以使用10053 event查看CBO优化器是如何做出选择的。由于我的功力还不够,对于10053事件还不是很明白,暂时就先不做演示了,要不哪说错了就不好了,这也可以做为以后博客分享内容

从这个事情上来看,我们对于一件事情应该做一个深入的研究,有充足的证据来证明,尤其是想要在某一方面有深入发展的时候。

猜你在找的Oracle相关文章