这两个脚本是Kerry Osborne分享的脚本, 经常会用到这两个脚本,是非常实用的SQL脚本.分享于此.希望对你有用.
脚本table_stats.sql
rem $Header$rem $Name$rem Copyright (c); 2004 by Hotsos Enterprises, Ltd.remrem Retrieve statistics information for a tableremrem Usage: SQL>@hstats <table name>rem---- Modified by Kerry Osborne-- commented out Histogram section-- added prompts-- added ability to run against table in another schmeaset echo off feed offset serveroutput on size 1000000accept ownname prompt 'Owner : 'accept tabname prompt 'Table : 'set lines 80define v_desc = '&ownname..&tabname.'desc &v_descset lines 200declarev_query varchar2(4000) ;v_owner varchar2(30) := upper('&&ownname');v_table varchar2(30) := upper('&&tabname');v_max_colname number ;v_max_ndv number ;v_max_nulls number ;v_max_bkts number ;v_max_smpl number ;v_max_endnum number ;v_max_endval number ;v_ct number ;prev_col varchar2(30) ;cursor col_stats isselect a.column_name, nvl(a.last_analyzed,to_date('01/01/1900','mm/dd/yyyy')) last_analyzed,decode(a.nullable,'N','NOT NULL',' ') nullable,a.num_distinct, a.density, a.num_nulls,a.num_buckets, a.avg_col_len, a.sample_sizefrom all_tab_columns awhere a.owner = v_ownerand a.table_name = v_table ;cursor hist_stats isselect b.column_name, b.endpoint_number, b.endpoint_value, b.endpoint_actual_valuefrom all_tab_histograms bwhere b.owner = v_ownerand b.table_name = v_tableand (exists (select 1 from all_tab_columnswhere num_buckets > 1and owner = b.ownerand table_name = b.table_nameand column_name = b.column_name)orexists (select 1 from all_tab_histogramswhere endpoint_number > 1and owner = b.ownerand table_name = b.table_nameand column_name = b.column_name))order by b.column_name, b.endpoint_number;procedure print_table ( p_query in varchar2, p_date_fmt in varchar2 default 'dd-MON-yyyy hh24:mi:ss' ) isl_theCursor integer default dbms_sql.open_cursor;l_columnValue varchar2(4000);l_status integer;l_descTbl dbms_sql.desc_tab;l_colCnt number;l_cs varchar2(255);l_date_fmt varchar2(255);-- Small inline procedure to restore the session's state.-- We may have modified the cursor sharing and nls date format-- session variables. This just restores them.procedure restoreisbeginif ( upper(l_cs) not in ( 'FORCE','SIMILAR' ))thenexecute immediate'alter session set cursor_sharing=exact';end if;if ( p_date_fmt is not null )thenexecute immediate'alter session set nls_date_format=''' || l_date_fmt || '''';end if;dbms_sql.close_cursor(l_theCursor);end restore;begin-- I like to see the dates print out with times, by default. The-- format mask I use includes that. In order to be "friendly"-- we save the current session's date format and then use-- the one with the date and time. Passing in NULL will cause-- this routine just to use the current date format.if ( p_date_fmt is not null )thenselect sys_context( 'userenv', 'nls_date_format' )into l_date_fmtfrom dual;execute immediate'alter session set nls_date_format=''' || p_date_fmt || '''';end if;-- To be bind variable friendly on ad-hoc queries, we-- look to see if cursor sharing is already set to FORCE or-- similar. If not, set it to force so when we parse literals-- are replaced with binds.if ( dbms_utility.get_parameter_value( 'cursor_sharing', l_status, l_cs ) = 1 )thenif ( upper(l_cs) not in ('FORCE','SIMILAR'))thenexecute immediate'alter session set cursor_sharing=force';end if;end if;-- Parse and describe the query sent to us. We need-- to know the number of columns and their names.dbms_sql.parse( l_theCursor, p_query, dbms_sql.native );dbms_sql.describe_columns( l_theCursor, l_colCnt, l_descTbl );-- Define all columns to be cast to varchar2s. We-- are just printing them out.for i in 1 .. l_colCnt loopdbms_sql.define_column(l_theCursor, i, l_columnValue, 4000);end loop;-- Execute the query, so we can fetch.l_status := dbms_sql.execute(l_theCursor);-- Loop and print out each column on a separate line.-- Bear in mind that dbms_output prints only 255 characters/line-- so we'll see only the first 200 characters by my design...while ( dbms_sql.fetch_rows(l_theCursor) > 0 )loopfor i in 1 .. l_colCnt loopdbms_sql.column_value( l_theCursor, i, l_columnValue );dbms_output.put_line( rpad( l_descTbl(i).col_name, 30 )|| ': ' ||substr( l_columnValue, 1, 200 ) );end loop;dbms_output.put_line( '-----------------' );end loop;-- Now, restore the session state, no matter what.restore;exceptionwhen others thenrestore;raise;end;begindbms_output.put_line('==========================================================================================');dbms_output.put_line(' Table Statistics');dbms_output.put_line('==========================================================================================');v_query := 'select table_name, last_analyzed, trim(degree) degree, partitioned,num_rows, chain_cnt, blocks, empty_blocks, avg_space,avg_row_len, monitoring, sample_sizefrom all_tableswhere owner = ''' || UPPER(v_owner) || ''' and table_name = ''' || UPPER(v_table) || '''';print_table (v_query);v_ct := 0 ;select count(1)into v_ctfrom all_tab_partitionswhere table_owner = v_ownerand table_name = v_table;if v_ct > 0 thendbms_output.put_line('==========================================================================================');dbms_output.put_line(' Partition Information');dbms_output.put_line('==========================================================================================');v_query := 'select partition_name, last_analyzed, high_value,num_rows, chain_cnt, blocks, empty_blocks,avg_space, avg_row_lenfrom all_tab_partitionswhere table_owner = ''' || UPPER(v_owner) || '''and table_name = ''' || UPPER(v_table) || '''';print_table (v_query);end if ;select max(length(column_name)) + 1, max(length(num_distinct)) + 3,max(length(num_nulls)) + 1, max(length(num_buckets)) + 1,max(length(sample_size)) + 1into v_max_colname, v_max_ndv, v_max_nulls, v_max_bkts, v_max_smplfrom all_tab_columnswhere owner = v_ownerand table_name = v_table ;if v_max_nulls < 8 thenv_max_nulls := 8 ;end if ;if v_max_bkts < 10 thenv_max_bkts := 10 ;end if ;if v_max_smpl < 7 thenv_max_smpl := 7;end if;dbms_output.put_line('==========================================================================================');dbms_output.put_line(' Column Statistics');dbms_output.put_line('==========================================================================================');dbms_output.put_line(' ' || rpad('Name',v_max_colname) || ' Analyzed Null? ' ||rpad(' NDV',v_max_ndv) || ' ' || rpad(' Density',10) ||rpad('# Nulls',v_max_nulls) || ' ' || rpad('# Buckets',v_max_bkts) || ' ' ||rpad('Sample',v_max_smpl) || ' Avg Col Len');dbms_output.put_line('==========================================================================================');for v_rec in col_stats loopdbms_output.put_line(rpad(v_rec.column_name,v_max_colname) || ' ' ||to_char(v_rec.last_analyzed,'mm/dd/yyyy') || ' ' ||v_rec.nullable || ' ' ||rpad(v_rec.num_distinct,v_max_ndv) ||to_char(v_rec.density,'9.999999') || ' ' ||rpad(v_rec.num_nulls,v_max_nulls) || ' ' ||rpad(v_rec.num_buckets,v_max_bkts) || ' ' ||rpad(v_rec.sample_size,v_max_smpl) || ' ' ||v_rec.avg_col_len );end loop ;select max(length(column_name)) + 1, max(length(endpoint_number)) + 1,max(length(endpoint_value)) + 1into v_max_colname, v_max_endnum, v_max_endvalfrom all_tab_histogramswhere owner = v_ownerand table_name = v_table ;if v_max_endnum < 12 thenv_max_endnum := 12 ;end if ;if v_max_endval < 16 thenv_max_endval := 16 ;end if ;select count(1)into v_ctfrom all_tab_histograms bwhere b.owner = v_ownerand b.table_name = v_tableand (exists (select 1 from all_tab_columnswhere num_buckets > 1and owner = b.ownerand table_name = b.table_nameand column_name = b.column_name)orexists (select 1 from all_tab_histogramswhere endpoint_number > 1and owner = b.ownerand table_name = b.table_nameand column_name = b.column_name));/* Histogram data commented outif v_ct > 0 thendbms_output.put_line('==========================================================================================');dbms_output.put_line(' Histogram Statistics');dbms_output.put_line('==========================================================================================');dbms_output.put_line(' ' || rpad('Name',v_max_colname) || ' ' ||rpad('Endpoint #',v_max_endnum) || ' ' ||rpad('Endpoint Value',v_max_endval) || ' Endpoint Actual Value');v_ct := 0 ;for v_rec in hist_stats loopif v_ct = 0 thenv_ct := 1 ;prev_col := v_rec.column_name ;elsif prev_col <> v_rec.column_name thendbms_output.put_line('------------------------------------------------------------------------------------------');prev_col := v_rec.column_name ;end if ;dbms_output.put_line(rpad(v_rec.column_name, v_max_colname) || ' ' ||rpad(v_rec.endpoint_number,v_max_endnum) || ' ' ||rpad(v_rec.endpoint_value,v_max_endval) || ' ' ||substr(v_rec.endpoint_actual_value,1,20) ) ;end loop ;end if ;*/v_ct := 0;select count(1)into v_ctfrom all_indexes awhere a.table_owner = v_ownerand a.table_name = v_table;if v_ct > 0 thendbms_output.put_line('==========================================================================================');dbms_output.put_line(' Index Information');dbms_output.put_line('==========================================================================================');v_query := 'select a.index_name, substr(a.index_type, 1, 4) index_type,a.last_analyzed, a.degree, a.partitioned, a.blevel,a.leaf_blocks, a.distinct_keys,a.avg_leaf_blocks_per_key, a.avg_data_blocks_per_key,a.clustering_factor, b.blocks blocks_in_table, b.num_rows rows_in_tablefrom all_indexes a, all_tables bwhere (a.table_name = b.table_name and a.table_owner = b.owner)and a.table_owner = ''' || UPPER(v_owner) || '''and a.table_name = ''' || UPPER(v_table) || '''' ;print_table (v_query);dbms_output.put_line('==========================================================================================');dbms_output.put_line(' Index Columns Information');dbms_output.put_line('==========================================================================================');dbms_output.put_line('Index Name Pos# Order Column Name Expression');dbms_output.put_line('==========================================================================================');end if;end ;/set verify off feed off numwidth 15 lines 500 heading offcolumn column_name format a30 heading 'Column Name'column index_name heading 'Index Name' format a30column column_position format 999999999 heading 'Position'column descend format a5 heading 'Order'column column_expression format a40 heading 'Expression'break on index_name skip 1select b.index_name, b.column_position, b.descend, b.column_name, e.column_expressionfrom all_ind_columns b, all_ind_expressions ewhere b.table_owner = upper('&ownname')and b.table_name = UPPER('&tabname')and b.index_name = e.index_name(+)order by b.index_name, b.column_position, b.column_name/undefine ownnameundefine tabnameset feed on numwidth 12 lines 120clear columnsclear breaksset lines 155set head on
脚本table_stats2.sql
set lines 155rem $Header$rem $Name$rem Copyright (c); 2004 by Hotsos Enterprises, Ltd.remrem Retrieve statistics information for a tableremrem Usage: SQL>@hstats <table name>rem---- Modified by Kerry Osborne-- commented out Histogram section-- added prompts-- added ability to run against table in another schmea-- added max and min values for column stats using display_raw function-- ordered column stats by column name-- Modified by Kerry Kong 2016-01-15 此脚本依赖函数DISPLAY_RAW, 执行前请执行脚本display_raw.sql创建此函数,并授权.set echo off feed offset serveroutput on size 1000000accept ownname prompt 'Owner : 'accept tabname prompt 'Table : 'set lines 80define v_desc = '&ownname..&tabname.'desc &v_descset lines 200declarev_query varchar2(4000) ;v_owner varchar2(30) := upper('&&ownname');v_table varchar2(30) := upper('&&tabname');v_max_colname number ;v_max_ndv number ;v_max_nulls number ;v_max_bkts number ;v_max_smpl number ;v_max_avg_col_len number ;v_max_low number ;v_max_high number ;v_max_endnum number ;v_max_endval number ;v_ct number ;prev_col varchar2(30) ;cursor col_stats isselect a.column_name, nvl(a.last_analyzed,to_date('01/01/1900','mm/dd/yyyy')) last_analyzed,decode(a.nullable,'N','NOT NULL',' ') nullable,a.num_distinct, a.density, a.num_nulls,a.num_buckets, a.avg_col_len, nvl(to_char(a.sample_size),' ') sample_size,display_raw(low_value,data_type) low_value, display_raw(high_value,data_type) high_valuefrom all_tab_columns awhere a.owner = v_ownerand a.table_name = v_tableorder by a.column_name;cursor hist_stats isselect b.column_name, b.endpoint_number, b.endpoint_value, b.endpoint_actual_valuefrom all_tab_histograms bwhere b.owner = v_ownerand b.table_name = v_tableand (exists (select 1 from all_tab_columnswhere num_buckets > 1and owner = b.ownerand table_name = b.table_nameand column_name = b.column_name)orexists (select 1 from all_tab_histogramswhere endpoint_number > 1and owner = b.ownerand table_name = b.table_nameand column_name = b.column_name))order by b.column_name, b.endpoint_number;procedure print_table ( p_query in varchar2, p_date_fmt in varchar2 default 'dd-MON-yyyy hh24:mi:ss' ) isl_theCursor integer default dbms_sql.open_cursor;l_columnValue varchar2(4000);l_status integer;l_descTbl dbms_sql.desc_tab;l_colCnt number;l_cs varchar2(255);l_date_fmt varchar2(255);-- Small inline procedure to restore the session's state.-- We may have modified the cursor sharing and nls date format-- session variables. This just restores them.procedure restoreisbeginif ( upper(l_cs) not in ( 'FORCE','SIMILAR' ))thenexecute immediate'alter session set cursor_sharing=exact';end if;if ( p_date_fmt is not null )thenexecute immediate'alter session set nls_date_format=''' || l_date_fmt || '''';end if;dbms_sql.close_cursor(l_theCursor);end restore;begin-- I like to see the dates print out with times, by default. The-- format mask I use includes that. In order to be "friendly"-- we save the current session's date format and then use-- the one with the date and time. Passing in NULL will cause-- this routine just to use the current date format.if ( p_date_fmt is not null )thenselect sys_context( 'userenv', 'nls_date_format' )into l_date_fmtfrom dual;execute immediate'alter session set nls_date_format=''' || p_date_fmt || '''';end if;-- To be bind variable friendly on ad-hoc queries, we-- look to see if cursor sharing is already set to FORCE or-- similar. If not, set it to force so when we parse literals-- are replaced with binds.if ( dbms_utility.get_parameter_value( 'cursor_sharing', l_status, l_cs ) = 1 )thenif ( upper(l_cs) not in ('FORCE','SIMILAR'))thenexecute immediate'alter session set cursor_sharing=force';end if;end if;-- Parse and describe the query sent to us. We need-- to know the number of columns and their names.dbms_sql.parse( l_theCursor, p_query, dbms_sql.native );dbms_sql.describe_columns( l_theCursor, l_colCnt, l_descTbl );-- Define all columns to be cast to varchar2s. We-- are just printing them out.for i in 1 .. l_colCnt loopdbms_sql.define_column(l_theCursor, i, l_columnValue, 4000);end loop;-- Execute the query, so we can fetch.l_status := dbms_sql.execute(l_theCursor);-- Loop and print out each column on a separate line.-- Bear in mind that dbms_output prints only 255 characters/line-- so we'll see only the first 200 characters by my design...while ( dbms_sql.fetch_rows(l_theCursor) > 0 )loopfor i in 1 .. l_colCnt loopdbms_sql.column_value( l_theCursor, i, l_columnValue );dbms_output.put_line( rpad( l_descTbl(i).col_name, 30 )|| ': ' ||substr( l_columnValue, 1, 200 ) );end loop;dbms_output.put_line( '-----------------' );end loop;-- Now, restore the session state, no matter what.restore;exceptionwhen others thenrestore;raise;end;begindbms_output.put_line('==========================================================================================');dbms_output.put_line(' Table Statistics');dbms_output.put_line('==========================================================================================');v_query := 'select table_name, last_analyzed, trim(degree) degree, partitioned,num_rows, chain_cnt, blocks, empty_blocks, avg_space,avg_row_len, monitoring, sample_sizefrom all_tableswhere owner = ''' || UPPER(v_owner) || ''' and table_name = ''' || UPPER(v_table) || '''';print_table (v_query);v_ct := 0 ;select count(1)into v_ctfrom all_tab_partitionswhere table_owner = v_ownerand table_name = v_table;if v_ct > 0 thendbms_output.put_line('==========================================================================================');dbms_output.put_line(' Partition Information');dbms_output.put_line('==========================================================================================');v_query := 'select partition_name, last_analyzed, high_value,num_rows, chain_cnt, blocks, empty_blocks,avg_space, avg_row_lenfrom all_tab_partitionswhere table_owner = ''' || UPPER(v_owner) || '''and table_name = ''' || UPPER(v_table) || '''';print_table (v_query);end if ;select max(length(column_name)) + 1, max(length(num_distinct)) + 3,max(length(num_nulls)) + 1, max(length(num_buckets)) + 1,max(length(sample_size)) + 1,max(length(avg_col_len)) + 1,max(length(display_raw(low_value,DATA_TYPE))) + 1,max(length(display_raw(high_value,DATA_TYPE))) + 1into v_max_colname, v_max_ndv, v_max_nulls, v_max_bkts, v_max_smpl, v_max_avg_col_len, v_max_low, v_max_highfrom all_tab_columnswhere owner = v_ownerand table_name = v_table ;if v_max_nulls < 8 thenv_max_nulls := 8 ;end if ;if v_max_bkts < 10 thenv_max_bkts := 10 ;end if ;if v_max_smpl < 7 thenv_max_smpl := 7;end if;if v_max_avg_col_len < 7 thenv_max_avg_col_len := 7;end if;if v_max_low < 4 thenv_max_low := 4;end if;if v_max_high < 4 thenv_max_high := 4;end if;dbms_output.put_line('===============================================================================================================================');dbms_output.put_line(' Column Statistics');dbms_output.put_line('===============================================================================================================================');dbms_output.put_line('' || rpad('Name',v_max_colname) || ' Analyzed Null? ' ||lpad(' NDV',v_max_ndv) || ' ' || lpad('Density',8) || ' ' ||lpad('# Nulls',v_max_nulls) || ' ' || lpad('# Buckets',v_max_bkts) || ' ' ||lpad('Sample',v_max_smpl) || ' ' || lpad('Avg Len',v_max_avg_col_len) || ' ' ||lpad('Min',v_max_low) || ' ' || lpad('Max',v_max_high));dbms_output.put_line('===============================================================================================================================');for v_rec in col_stats loopdbms_output.put_line(rpad(v_rec.column_name,v_max_colname) || ' ' ||to_char(v_rec.last_analyzed,'mm/dd/yyyy') || ' ' ||v_rec.nullable || ' ' ||lpad(v_rec.num_distinct,v_max_ndv) || ' ' ||to_char(v_rec.density,'9.999999') || ' ' ||lpad(v_rec.num_nulls,v_max_nulls) || ' ' ||lpad(v_rec.num_buckets,v_max_bkts) || ' ' ||lpad(v_rec.sample_size,v_max_smpl) || ' ' ||lpad(v_rec.avg_col_len,v_max_avg_col_len) || ' ' ||lpad(v_rec.low_value,v_max_low) || ' ' ||lpad(v_rec.high_value,v_max_high));end loop ;select max(length(column_name)) + 1, max(length(endpoint_number)) + 1,max(length(endpoint_value)) + 1into v_max_colname, v_max_endnum, v_max_endvalfrom all_tab_histogramswhere owner = v_ownerand table_name = v_table ;if v_max_endnum < 12 thenv_max_endnum := 12 ;end if ;if v_max_endval < 16 thenv_max_endval := 16 ;end if ;select count(1)into v_ctfrom all_tab_histograms bwhere b.owner = v_ownerand b.table_name = v_tableand (exists (select 1 from all_tab_columnswhere num_buckets > 1and owner = b.ownerand table_name = b.table_nameand column_name = b.column_name)orexists (select 1 from all_tab_histogramswhere endpoint_number > 1and owner = b.ownerand table_name = b.table_nameand column_name = b.column_name));/* Histogram data commented outif v_ct > 0 thendbms_output.put_line('==========================================================================================');dbms_output.put_line(' Histogram Statistics');dbms_output.put_line('==========================================================================================');dbms_output.put_line(' ' || rpad('Name',v_max_colname) || ' ' ||rpad('Endpoint #',v_max_endnum) || ' ' ||rpad('Endpoint Value',v_max_endval) || ' Endpoint Actual Value');v_ct := 0 ;for v_rec in hist_stats loopif v_ct = 0 thenv_ct := 1 ;prev_col := v_rec.column_name ;elsif prev_col <> v_rec.column_name thendbms_output.put_line('------------------------------------------------------------------------------------------');prev_col := v_rec.column_name ;end if ;dbms_output.put_line(rpad(v_rec.column_name, v_max_colname) || ' ' ||rpad(v_rec.endpoint_number,v_max_endnum) || ' ' ||rpad(v_rec.endpoint_value,v_max_endval) || ' ' ||substr(v_rec.endpoint_actual_value,1,20) ) ;end loop ;end if ;*/v_ct := 0;select count(1)into v_ctfrom all_indexes awhere a.table_owner = v_ownerand a.table_name = v_table;if v_ct > 0 thendbms_output.put_line('===============================================================================================================================');dbms_output.put_line(' Index Information');dbms_output.put_line('===============================================================================================================================');v_query := 'select a.index_name, substr(a.index_type, 1, 4) index_type,a.last_analyzed, a.degree, a.partitioned, a.blevel,a.leaf_blocks, a.distinct_keys,a.avg_leaf_blocks_per_key, a.avg_data_blocks_per_key,a.clustering_factor, b.blocks blocks_in_table, b.num_rows rows_in_tablefrom all_indexes a, all_tables bwhere (a.table_name = b.table_name and a.table_owner = b.owner)and a.table_owner = ''' || UPPER(v_owner) || '''and a.table_name = ''' || UPPER(v_table) || '''' ;print_table (v_query);dbms_output.put_line('==========================================================================================');dbms_output.put_line(' Index Columns Information');dbms_output.put_line('==========================================================================================');dbms_output.put_line('Index Name Pos# Order Column Name Expression');dbms_output.put_line('==========================================================================================');end if;end ;/set verify off feed off numwidth 15 lines 500 heading offcolumn column_name format a30 heading 'Column Name'column index_name heading 'Index Name' format a30column column_position format 999999999 heading 'Position'column descend format a5 heading 'Order'column column_expression format a40 heading 'Expression'break on index_name skip 1select b.index_name, b.column_position, b.descend, b.column_name, e.column_expressionfrom all_ind_columns b, all_ind_expressions ewhere b.table_owner = upper('&ownname')and b.table_name = UPPER('&tabname')and b.index_name = e.index_name(+)order by b.index_name, b.column_position, b.column_name/undefine ownnameundefine tabnameset feed on numwidth 12 lines 120clear columnsclear breaksset lines 155set head on
脚本table_stats2.sql依赖函数display_raw, 如果你想使用table_stats2.sql,必须在数据库创建函数display_raw,并根据实际使用场景进行授权.
create or replace function display_raw (rawval raw, type varchar2)return varchar2iscn number;cv varchar2(64);cd date;cnv nvarchar2(64);cr rowid;cc char(64);cbf binary_float;cbd binary_double;beginif (type = 'VARCHAR2') thendbms_stats.convert_raw_value(rawval, cv);return to_char(cv);elsif (type = 'DATE') thendbms_stats.convert_raw_value(rawval, cd);return to_char(cd);elsif (type = 'NUMBER') thendbms_stats.convert_raw_value(rawval, cn);return to_char(cn);elsif (type = 'BINARY_FLOAT') thendbms_stats.convert_raw_value(rawval, cbf);return to_char(cbf);elsif (type = 'BINARY_DOUBLE') thendbms_stats.convert_raw_value(rawval, cbd);return to_char(cbd);elsif (type = 'NVARCHAR2') thendbms_stats.convert_raw_value(rawval, cnv);return to_char(cnv);elsif (type = 'ROWID') thendbms_stats.convert_raw_value(rawval, cr);return to_char(cr);elsif (type = 'CHAR') thendbms_stats.convert_raw_value(rawval, cc);return to_char(cc);elsereturn 'UNKNOWN DATATYPE';end if;end;/show errors
文章转载自DBA闲思杂想录,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




