Oracle not reuse deleted blocks - oracle

I'm trying to insert data from PURCHASE_HIST_D to PURCHASE_HIST.
(different schemas in different servers, with DBLINK).
The target table has a lot of deleted data blocks.
This is how I'm checking the segments vs the used blocks:
-- result : 199.8743480481207370758056640625 GB
select (AVG_ROW_LEN*NUM_ROWS)/1024/1024/1024 from DBA_TABLES where TABLE_NAME='PURCHASE_HIST';
-- result: 250.7939453125 GB
select SUM(BYTES)/1024/1024/1024 from DBA_SEGMENTS where SEGMENT_NAME='PURCHASE_HIST';
which means that there are 50 GB of used blocks which can be reuse for the new data.
I'm query the same for the source table:
-- result: 21.8079682849347591400146484375
select (AVG_ROW_LEN*NUM_ROWS)/1024/1024/1024 from DBA_TABLES where TABLE_NAME='PURCHASE_HIST_D';
-- result: 27.447265625
select SUM(BYTES)/1024/1024/1024 from DBA_SEGMENTS where SEGMENT_NAME='PURCHASE_HIST_D';
The source is only 27 GB so It's looks like I dont need to add more space for the tablespace.
This is the free tablespace information:
-- result: 1889477 (Used MB) 4923 (Free MB) 1894400 (Total MB)
select
fs.tablespace_name "Tablespace",
(df.totalspace - fs.freespace) "Used MB",
fs.freespace "Free MB",
df.totalspace "Total MB",
round(100 * (fs.freespace / df.totalspace)) "Pct. Free"
from
(select
tablespace_name,
round(sum(bytes) / 1048576) TotalSpace
from
dba_data_files
group by
tablespace_name
) df,
(select
tablespace_name,
round(sum(bytes) / 1048576) FreeSpace
from
dba_free_space
group by
tablespace_name
) fs
WHERE
DF.TABLESPACE_NAME = FS.TABLESPACE_NAME
and df.TABLESPACE_NAME = 'TS_DWHDATA';
So why when I'm execute the insert (even with NOAPPEND hint) I get an error that there is no enough space in tablesapce?
-- examole of the Insert
INSERT
/*+ monitor NOAPPEND parallel(64) statement_queuing */
INTO DWH.PURCHASE_HIST
SELECT *
FROM DWH_MIG.PURCHASE_HIST_D#DWH_MIG ;
The exception:
ORA-01653: unable to extend table DWH.PURCHASE_HIST by 8192 in tablespace TS_DWHDATA

You are getting the free space (using query) from the table but the high watermark is still at the point from where you can not insert data below that.
You need to reclaim that space using the following:
alter table your_table enable row movement;
alter table your_table shrink space cascade;
Also, You will need to rebuild the indexes of the table after such an operation.
Refer Oracle documentation for reclaiming waste space.
Cheers!!

Related

ORACLE - Get database size per partition

I am looking for an SQL query to give me that kind of output:
table_owner table_name partition_name data (bytes) indexes (bytes)
MY_OWNER MY_TABLE P01 12345678 23456789
MY_OWNER MY_TABLE P02 34567890 45678901
MY_OWNER MY_TABLE P03 56789012 67890123
...
I visited How do I calculate tables size in Oracle but didn't find what I am looking for, because it is always per table, per owner/schema but never per partition.
I know that the amount in bytes may not really be representative of the reality since it could be "real bytes in disk" and/or "bytes preallocated" (and real data could only use 1% of this preallocated space), but I am open to have this value even if it is the preallocated or the real amount of bytes used.
Notes:
Using Oracle 18c Enterprise
We do NOT care about system tables, ORACLE tables, maintenance tables, etc. just focusing on tables created by myself for the data
Tablespace name is ALWAYS the same for all partitions in all tables in the same schema, and of course each tablespace name is different for each schema
No need to round in Kb, Mb, Gb or even Tb, if possible I would prefer it in bytes.
No need of pourcentage, no need of max space available
I only use partitions, NOT any subpartitions
I can use a PL/SQL block if we need to loop on each schema, table and partition
Guessing I can run this query by any user
Any idea?
Hi something like this? We use a similar query that I've modified. You would have to change your ORDER BY clause as you wish, and maybe limit it to one owner as it could take long over the whole database. For that reason we don't join to segments for size, but only look at rows and blocks.
select "OWNER", "OBJECT", "TYPE", "PARTITION_NAME", "NUM_ROWS", "GB", "PARTITION_POSITION", "DUMMY"
from ((select tp.table_owner owner, tp.TABLE_NAME object, 'TABLE' type, tp.PARTITION_NAME,ROUND(s.bytes/1024/1024/1024, 2) GB, tp.NUM_ROWS,tp.PARTITION_POSITION, 1 dummy
from dba_tab_partitions tp, dba_tables t, dba_segments s
where t.table_name=tp.table_name and t.table_name=s.segment_name )
union
(select ip.index_owner owner,ip.INDEX_NAME object, 'INDEX' type, ip.PARTITION_NAME,ROUND(s.bytes/1024/1024/1024, 2) GB,ip.NUM_ROWS, ip.PARTITION_POSITION, 2 dummy
from dba_ind_partitions ip, dba_indexes i, dba_tables t, dba_segments s
where i.index_name=ip.index_name and i.table_name=t.table_name and i.index_name=s.segment_name )
union
(select lp.table_owner owner,lp.LOB_NAME object, 'LOB' type, lp.PARTITION_NAME, 0, ROUND(s.bytes/1024/1024/1024, 2) GB,lp.PARTITION_POSITION, 3 dummy
from dba_lob_partitions lp, dba_tables t, dba_segments s
where t.table_name=lp.table_name and t.table_name=s.segment_name ))
order by 8,1,2,7;

Query to check the full schema scan for tables in Oracle DB

Hi I have a requirement to scan through the schema and identify the tables which are redundant (candidate for dropping) ,so i did a select in DBA_Dependencies to check whether the tables are being used in any of the DB object types like (Procedure, package body, views, Materialized views....) i was able to find some tables and excluded the tables ,since i also need to capture the total counts, when the table was last loaded/used is there a automated way to select only selected tables (not found in dependencies list) and capture the counts and also when it was used/loaded
Difficulty - so many tables 500+
i have used the below query
Query 1
select table_name,
to_number(extractvalue(xmltype(dbms_xmlgen.getxml('select count(*) c from '||owner||'.'||table_name)),'/ROWSET/ROW/C')) as count
from all_tables
where owner = 'SCHEMA_NAME'
Query 2
select owner, table_name, num_rows, sample_size, last_analyzed from all_tables;
Query 1 Result
Filter Table_name=CUST_ORDER
OWNER TABLE_NAME COUNT SAMPLE_SIZE LAST_ANALYZED
ABCD CUST_ORDER 1083 1023 01.01.2020
Query 2 Result
Filter Table_name=CUST_ORDER
OWNER TABLE_NAME NUM_ROWS SAMPLE_SIZE LAST_ANALYZED
ABCD CUST_ORDER 1023 1023 01.01.2020
Question
Query 1 - Results not matching when compared with query 2 ,since the same table and filter is applied
in both the queries and why the results are not matching ?
but when i randomly checked other filter it is matching , does any one know the reason ?
Upon further testing i encountered an error ,what does this error signify permissions ?
ORA-29913: error in executing ODCIEXTTABLEOPEN callout
ORA-29400: data cartridge error
KUP-04040: file **-**.csv in ****_***_***_***** not found
29913. 00000 - "error in executing %s callout"
*Cause: The execution of the specified callout caused an error.
*Action: Examine the error messages take appropriate action.
The number you see on all_tables is a point in time capture of the number of rows. It will only be updated if the statistics are rebuilt for that table.
Here is an example:
CREATE TABLE t1 AS
SELECT *
FROM all_objects;
SELECT t.num_rows
FROM all_tables t
WHERE t.table_name = 'T1';
-- 78570
SELECT COUNT(*)
FROM t1;
-- 78570
The stats and the physical number of rows match!
INSERT INTO t1
SELECT *
FROM all_objects ao
WHERE rownum <= 5;
-- 5 rows inserted
SELECT t.num_rows
FROM all_tables t
WHERE t.table_name = 'T1';
-- 78570
SELECT COUNT(*)
FROM t1;
-- 78575
Here we have the mis-match because rows were inserted (or maybe even deleted), but the stats for the table have not been updated. Let's update them:
BEGIN
dbms_stats.gather_table_stats(ownname => 'SCHEMA',
tabname => 'T1');
END;
/
SELECT t.num_rows
FROM all_tables t
WHERE t.table_name = 'T1';
-- 78575
Now you can see the rows match. Using the value from all_tables may be good enough for your research (and will certainly be faster to query than counting every table).
Query - 1 is actual data of the table and hence it is accurate data. One can rely on this query's output.
Query - 2 is not actual data. It is the data captured when table was last analyzed and one should not be dependant on this query for finding number of records in the table.
You can gather the stats on this table and execute the query-2 then you will find the same data as query-1
If records are not inserted or deleted from the table after stats are gathered, then query-1 and query-2 data will match for that table.

Oracle - exchange partitions with a table

I try to create a table2 on Oracle 11g.2.0.3 with:
CREATE table2
LOGGING TABLESPACE TS_table1_2014 PCTFREE 10 INITRANS 1 STORAGE ( INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS UNLIMITED BUFFER_POOL DEFAULT ) NOCOMPRESS
as (select * from table1 where date_text <= '2015-12-31');
and I have received error below when I try to exchange this table2 with a partitioned table3:
alter table table3 exchange partition partition_name WITH TABLE table2;
Error report -
SQL Error: ORA-14097: column type or size mismatch in ALTER TABLE EXCHANGE PARTITION
14097. 00000 - "column type or size mismatch in ALTER TABLE EXCHANGE PARTITION"
*Cause: The corresponding columns in the tables specified in the
ALTER TABLE EXCHANGE PARTITION are of different type or size
*Action: Ensure that the two tables have the same number of columns
with the same type and size.
I have test diferences with query below:
Select a.COLUMN_NAME
, a.DATA_TYPE, b.DATA_TYPE
, a.data_length, b.data_length
, a.data_precision, b.data_precision
, a.data_scale, b.data_scale
, a.nullable, b.nullable
from ALL_TAB_COLUMNS a
full outer join ALL_TAB_COLUMNS b on a.column_name=b.column_name
and b.owner=user and b.table_name='&table2'
where a.owner=user and a.table_name='&table1'
and (
nvl(a.data_type,'#')!=nvl(b.data_type,'#')
or nvl(a.data_length,-1)!=nvl(b.data_length,-1)
or nvl(a.data_precision,-100)!=nvl(b.data_precision,-100)
or nvl(a.data_scale,-100)!=nvl(b.data_scale,-100)
or nvl(a.nullable,'#')!=nvl(b.nullable,'#')
)
;
Some differences resulted are in a column size. This syntax "create as select" didn't keep order and size for new table created.
How can I create table2 as select from table1 with force keep same size columns as primary table1 source?
Thanks!
I can't find any differences in your DDL. What I suggest is to use the same DDL to create table2, then do:
insert into table2 select * from table1;
You need to use dbms_metadata package or query number of data dictionary views like all_tab_columns and etc to get metadata about existing table so you can construct correct sql for swap-table (used in exchange partition operation). CTAS does not transfer DEFAULT values for example and constraints except NOT NULL checks.
The best practice is to create/re-create/modify this table simultaneously with partitioned table.

Manage Increase MAX BYTES or Decrease USED BYTES ORACLE TABLESPACE

I have one problem while creating external table which has 3.2 million records
The external file has 3.2 million records as a .CSV file format and I have created the EXTERNAL file in Oracle,
CREATE TABLE SCOT.RXD32LExt
(
SORT_CODE NUMBER(9),
ACCOUNT_NUM NUMBER(11),
BANK_NAME VARCHAR2(6),
TRAN_DEBIT NUMBER(9),
TRAN_CREDIT NUMBER(9),
SEQ_NUM NUMBER(11),
RXD_FLAG NUMBER(4),
REPORT_FLAG NUMBER(4),
FLAG VARCHAR2(4)
)
ORGANIZATION EXTERNAL
(
TYPE ORACLE_LOADER
DEFAULT DIRECTORY GK3_F
ACCESS PARAMETERS
(
records delimited by newline
fields terminated by ','
optionally enclosed by '"'
missing field values are null
(
SORT_CODE, ACCOUNT_NUM, BANK_NAME, TRAN_DEBIT, TRAN_CREDIT,
SEQ_NUM, RXD_FLAG, REPORT_FLAG, FLAG
)
)
LOCATION ('32LRecords.csv')
)
PARALLEL
REJECT LIMIT UNLIMITED;
Table Created.
SQL> SELECT * FROM SCOT.RXD32LExt;
My database is facing memory issue out of bound exception. since SYSTEM user is not having sufficient space in database and I have check the below query for tablespace
SELECT TABLESPACE_NAME,
SUM(bytes)/1024/1024 "USED MEGABYTES",
SUM(maxbytes)/1024/1024 "MAX MEGABYTES"
FROM dba_data_files
WHERE tablespace_name IN ('SYSTEM', 'USERS')
GROUP BY tablespace_name;
Output
------
TABLESPACE_NAME - USED MEGABYTES - MAX MEGABYTES
----------------------------------------------
USERS 100 11264
SYSTEM 600 600
If I need to DECREASE USED MEGABYTES means what i need to do or
If I need to INCREASE MAX MEGABYTES MEANS what I need to do.
I did the following query
ALTER DATABASE DATAFILE
'C:\ORACLEXE\APP\ORACLE\ORADATA\XE\SYSTEM.DBF' RESIZE 10G;
but the above alter query has increase the used megabytes memory of not max memory.
TABLESPACE_NAME - USED MEGABYTES - MAX MEGABYTES
----------------------------------------------
USERS 100 11264
SYSTEM 3200 600

Oracle: Determine Partition Size

I have a table with 200 hash partitions, I like to monitor daily size growth (rows and size in MB) for each of the partition. For more information, another process loads / updates rows on this table on daily basis and I like to know the growth pattern.
I am not looking for overall table size script, but size of each partition.
You can check the size of your partitions with this statement:
SELECT partition_name, bytes/1024/1024 "MB"
FROM dba_segments
WHERE segment_name = 'MYTABLE'
AND segment_type = 'TABLE PARTITION';

Resources