oracle 如何判断 ALL_TAB_COLS 中哪些列未使用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2949226/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can you tell which columns are unused in ALL_TAB_COLS?
提问by thecoop
When you query the ALL_TAB_COLS view on Oracle 9i, it lists columns marked as UNUSED as well as the 'active' table columns. There doesn't seem to be a field that explicitly says whether a column is UNUSED, or any view I can join to that lists the unused columns in a table. How can I easily find out which are the unused columns, so I can filter them out of ALL_TAB_COLS?
当您在 Oracle 9i 上查询 ALL_TAB_COLS 视图时,它会列出标记为 UNUSED 的列以及“活动”表列。似乎没有一个字段明确说明某列是否未使用,或者我可以加入的任何视图都列出了表中未使用的列。如何轻松找出哪些是未使用的列,以便从 ALL_TAB_COLS 中过滤掉它们?
回答by Tony Andrews
Try using ALL_TAB_COLUMNS instead of ALL_TAB_COLS. In Oracle 11.2 I find that unused columns appear in ALL_TAB_COLS (though renamed) but not in ALL_TAB_COLUMNS.
尝试使用 ALL_TAB_COLUMNS 而不是 ALL_TAB_COLS。在 Oracle 11.2 中,我发现未使用的列出现在 ALL_TAB_COLS(虽然重命名)中,但没有出现在 ALL_TAB_COLUMNS 中。
I created a table like this:
我创建了一个这样的表:
create table t1 (c1 varchar2(30), c2 varchar2(30);
Then set c2 unused:
然后设置 c2 未使用:
alter table t1 set unused column c2;
Then I see:
然后我看到:
select column_name from all_tab_cols where owner='ME' and table_name='T1';
COLUMN_NAME
-----------
C1
SYS_C00002_10060107:25:40$
select column_name from all_tab_columns where owner='ME' and table_name='T1';
COLUMN_NAME
-----------
C1
回答by Allan
The only filter in the definition of ALL_TAB_COLUMNS is "where hidden_column = 'NO'", so it seems that UNUSED columns are flagged in the HIDDEN_COLUMN field.
ALL_TAB_COLUMNS 定义中唯一的过滤器是“where hidden_column = 'NO'”,因此似乎在 HIDDEN_COLUMN 字段中标记了 UNUSED 列。
Looking further into the data definition views, it looks like COL$.PROPERTY gets set to 32800 (bits 2^5 and 2^15) when the column becomes UNUSED. 2^5 is used to mark hidden columns, so it seems likely 2^15 is UNUSED. You could create a custom version of ALL_TAB_COLS based on that which should work for what you need, such as this.
进一步查看数据定义视图,当列变为 UNUSED 时,COL$.PROPERTY 看起来像设置为 32800(位 2^5 和 2^15)。2^5 用于标记隐藏列,因此 2^15 似乎是未使用的。您可以创建一个自定义版本的 ALL_TAB_COLS 基于应该适合您需要的版本,例如这个。
CREATE OR REPLACE FORCE VIEW all_tab_cols_rev (owner,
table_name,
column_name,
data_type,
data_type_mod,
data_type_owner,
data_length,
data_precision,
data_scale,
nullable,
column_id,
default_length,
data_default,
num_distinct,
low_value,
high_value,
density,
num_nulls,
num_buckets,
last_analyzed,
sample_size,
character_set_name,
char_col_decl_length,
global_stats,
user_stats,
avg_col_len,
char_length,
char_used,
v80_fmt_image,
data_upgraded,
hidden_column,
virtual_column,
segment_column_id,
internal_column_id,
histogram,
qualified_col_name,
unused_column)
AS
SELECT u.NAME,
o.NAME,
c.NAME,
DECODE (c.type#,
1, DECODE (c.CHARSETFORM, 2, 'NVARCHAR2', 'VARCHAR2'),
2, DECODE (c.scale, NULL, DECODE (c.precision#, NULL, 'NUMBER', 'FLOAT'), 'NUMBER'),
8, 'LONG',
9, DECODE (c.CHARSETFORM, 2, 'NCHAR VARYING', 'VARCHAR'),
12, 'DATE',
23, 'RAW',
24, 'LONG RAW',
58, NVL2 (ac.synobj#, (SELECT o.NAME
FROM obj$ o
WHERE o.obj# = ac.synobj#), ot.NAME),
69, 'ROWID',
96, DECODE (c.CHARSETFORM, 2, 'NCHAR', 'CHAR'),
100, 'BINARY_FLOAT',
101, 'BINARY_DOUBLE',
105, 'MLSLABEL',
106, 'MLSLABEL',
111, NVL2 (ac.synobj#, (SELECT o.NAME
FROM obj$ o
WHERE o.obj# = ac.synobj#), ot.NAME),
112, DECODE (c.CHARSETFORM, 2, 'NCLOB', 'CLOB'),
113, 'BLOB',
114, 'BFILE',
115, 'CFILE',
121, NVL2 (ac.synobj#, (SELECT o.NAME
FROM obj$ o
WHERE o.obj# = ac.synobj#), ot.NAME),
122, NVL2 (ac.synobj#, (SELECT o.NAME
FROM obj$ o
WHERE o.obj# = ac.synobj#), ot.NAME),
123, NVL2 (ac.synobj#, (SELECT o.NAME
FROM obj$ o
WHERE o.obj# = ac.synobj#), ot.NAME),
178, 'TIME(' || c.scale || ')',
179, 'TIME(' || c.scale || ')' || ' WITH TIME ZONE',
180, 'TIMESTAMP(' || c.scale || ')',
181, 'TIMESTAMP(' || c.scale || ')' || ' WITH TIME ZONE',
231, 'TIMESTAMP(' || c.scale || ')' || ' WITH LOCAL TIME ZONE',
182, 'INTERVAL YEAR(' || c.precision# || ') TO MONTH',
183, 'INTERVAL DAY(' || c.precision# || ') TO SECOND(' || c.scale || ')',
208, 'UROWID',
'UNDEFINED'),
DECODE (c.type#, 111, 'REF'),
NVL2 (ac.synobj#, (SELECT u.NAME
FROM user$ u, obj$ o
WHERE o.owner# = u.user#
AND o.obj# = ac.synobj#), ut.NAME),
c.LENGTH,
c.precision#,
c.scale,
DECODE (SIGN (c.null$), -1, 'D', 0, 'Y', 'N'),
DECODE (c.col#, 0, TO_NUMBER (NULL), c.col#),
c.deflength,
c.default$,
h.distcnt,
h.lowval,
h.hival,
h.density,
h.null_cnt,
CASE
WHEN NVL (h.distcnt, 0) = 0
THEN h.distcnt
WHEN h.row_cnt = 0
THEN 1
WHEN ( h.bucket_cnt > 255
OR ( h.bucket_cnt > h.distcnt
AND h.row_cnt = h.distcnt
AND h.density * h.bucket_cnt <= 1) )
THEN h.row_cnt
ELSE h.bucket_cnt
END,
h.timestamp#,
h.sample_size,
DECODE (c.CHARSETFORM,
1, 'CHAR_CS',
2, 'NCHAR_CS',
3, NLS_CHARSET_NAME (c.CHARSETID),
4, 'ARG:' || c.CHARSETID),
DECODE (c.CHARSETID, 0, TO_NUMBER (NULL), NLS_CHARSET_DECL_LEN (c.LENGTH, c.CHARSETID) ),
DECODE (BITAND (h.spare2, 2), 2, 'YES', 'NO'),
DECODE (BITAND (h.spare2, 1), 1, 'YES', 'NO'),
h.avgcln,
c.spare3,
DECODE (c.type#,
1, DECODE (BITAND (c.property, 8388608), 0, 'B', 'C'),
96, DECODE (BITAND (c.property, 8388608), 0, 'B', 'C'),
NULL),
DECODE (BITAND (ac.flags, 128), 128, 'YES', 'NO'),
DECODE (o.status,
1, DECODE (BITAND (ac.flags, 256), 256, 'NO', 'YES'),
DECODE (BITAND (ac.flags, 2),
2, 'NO',
DECODE (BITAND (ac.flags, 4), 4, 'NO', DECODE (BITAND (ac.flags, 8), 8, 'NO', 'N/A') ) ) ),
DECODE (c.property, 0, 'NO', DECODE (BITAND (c.property, 32), 32, 'YES', 'NO') ),
DECODE (c.property, 0, 'NO', DECODE (BITAND (c.property, 8), 8, 'YES', 'NO') ),
DECODE (c.segcol#, 0, TO_NUMBER (NULL), c.segcol#),
c.intcol#,
CASE
WHEN NVL (h.row_cnt, 0) = 0
THEN 'NONE'
WHEN ( h.bucket_cnt > 255
OR ( h.bucket_cnt > h.distcnt
AND h.row_cnt = h.distcnt
AND h.density * h.bucket_cnt <= 1) )
THEN 'FREQUENCY'
ELSE 'HEIGHT BALANCED'
END,
DECODE (BITAND (c.property, 1024),
1024, (SELECT DECODE (BITAND (cl.property, 1), 1, rc.NAME, cl.NAME)
FROM SYS.col$ cl, attrcol$ rc
WHERE cl.intcol# = c.intcol# - 1
AND cl.obj# = c.obj#
AND c.obj# = rc.obj#(+)
AND cl.intcol# = rc.intcol#(+)),
DECODE (BITAND (c.property, 1), 0, c.NAME, (SELECT tc.NAME
FROM SYS.attrcol$ tc
WHERE c.obj# = tc.obj#
AND c.intcol# = tc.intcol#) ) ),
DECODE (c.property, 0, 'NO', DECODE (BITAND (c.property, 32768), 32768, 'YES', 'NO') )
FROM SYS.col$ c, SYS.obj$ o, SYS.hist_head$ h, SYS.user$ u, SYS.coltype$ ac, SYS.obj$ ot, SYS.user$ ut
WHERE o.obj# = c.obj#
AND o.owner# = u.user#
AND c.obj# = h.obj#(+)
AND c.intcol# = h.intcol#(+)
AND c.obj# = ac.obj#(+)
AND c.intcol# = ac.intcol#(+)
AND ac.toid = ot.oid$(+)
AND ot.type#(+) = 13
AND ot.owner# = ut.user#(+)
AND ( o.type# IN (3, 4) /* cluster, view */
OR ( o.type# = 2 /* tables, excluding iot - overflow and nested tables */
AND NOT EXISTS (
SELECT NULL
FROM SYS.tab$ t
WHERE t.obj# = o.obj#
AND ( BITAND (t.property, 512) = 512
OR BITAND (t.property, 8192) = 8192) ) ) )
AND ( o.owner# = USERENV ('SCHEMAID')
OR o.obj# IN (SELECT obj#
FROM SYS.objauth$
WHERE grantee# IN (SELECT kzsrorol
FROM x$kzsro) )
OR /* user has system privileges */
EXISTS (
SELECT NULL
FROM v$enabledprivs
WHERE priv_number IN
(-45 /* LOCK ANY TABLE */,
-47 /* SELECT ANY TABLE */,
-48 /* INSERT ANY TABLE */,
-49 /* UPDATE ANY TABLE */,
-50 /* DELETE ANY TABLE */) ) );
I'd put the view in a separate, locked schema that has the SELECT ANY DICTIONARY privilege, then create a public synonym for it. That way, all of your users would be able to see the UNUSED_COLUMN column for only the tables that they have permissions on.
我会将视图放在一个单独的、锁定的模式中,该模式具有 SELECT ANY DICTIONARY 权限,然后为它创建一个公共同义词。这样,您的所有用户都只能看到他们拥有权限的表的 UNUSED_COLUMN 列。