此脚本不依赖统计信息。

    在开发过程中,我们应该尽量避免编写 SELECT * 这种 SQL。SELECT * 这种 SQL,走索引无法避免回表,走 HASH 连接的时候会将驱动表所有的列放入 PGA 中,浪费 PGA 内存。执行计划中(V$SQL_PLAN/PLAN_TABLE),projection 字段表示访问了哪些字段,如果 projection 字段中字段个数等于表的字段总个数,那么我们就可以判断 SQL 语句使用了 SELECT *。以下脚本抓出 SELECT * 的 SQL。

    1. select a.sql_id, a.sql_text, c.owner, d.table_name, d.column_cnt, c.size_mb
    2. from v$sql a,
    3. v$sql_plan b,
    4. (select owner, segment_name, sum(bytes / 1024 / 1024) size_mb
    5. from dba_segments
    6. group by owner, segment_name) c,
    7. (select owner, table_name, count(*) column_cnt
    8. from dba_tab_cols
    9. group by owner, table_name) d
    10. where a.sql_id = b.sql_id
    11. and a.child_number = b.child_number
    12. and b.object_owner = c.owner
    13. and b.object_name = c.segment_name
    14. and b.object_owner = d.owner
    15. and b.object_name = d.table_name
    16. and REGEXP_COUNT(b.projection, ']') = d.column_cnt
    17. and c.owner = 'SCOTT'
    18. order by 6 desc;

    我们在 Scott 账户中运行如下 SQL。

    1. select * from t where object_id<1000;

    我们使用脚本将其抓出。

    1. select a.sql_id, a.sql_text, c.owner, d.table_name, d.column_cnt, c.size_mb
    2. from v$sql a,
    3. v$sql_plan b,
    4. (select owner, segment_name, sum(bytes / 1024 / 1024) size_mb
    5. from dba_segments
    6. group by owner, segment_name) c,
    7. (select owner, table_name, count(*) column_cnt
    8. from dba_tab_cols
    9. group by owner, table_name) d
    10. where a.sql_id = b.sql_id
    11. and a.child_number = b.child_number
    12. and b.object_owner = c.owner
    13. and b.object_name = c.segment_name
    14. and b.object_owner = d.owner
    15. and b.object_name = d.table_name
    16. and REGEXP_COUNT(b.projection, ']') = d.column_cnt
    17. and c.owner = 'SCOTT'
    18. order by 6 desc;
    1. SQL_ID SQL_TEXT OWNER TABLE_NAME COLUMN_CNT SIZE_MB
    2. ---------- ----------------------------------- ------ -------- --------- ---------
    3. ga64bhp5fxhtn select * from t where object_id<1000 SCOTT T 15 9