Tuesday, September 30, 2025
clean up
Monday, September 29, 2025
tablespace drop
SELECT p.table_owner AS schema_name, p.table_name, p.partition_name, p.high_value AS partition_range, -- For range partitions; shows the upper bound ROUND(SUM(s.bytes) / 1024 / 1024 / 1024, 2) AS approx_size_gb, -- Approximate size as a proxy if counts are expensive 'SELECT COUNT(*) FROM ' || p.table_owner || '.' || p.table_name || ' PARTITION (' || p.partition_name || ');' AS count_query -- Generate query for exact row count FROM dba_tab_partitions p JOIN dba_segments s ON p.table_owner = s.owner AND p.table_name = s.segment_name AND p.partition_name = s.partition_name WHERE p.table_owner = 'YOUR_SCHEMA_NAME' -- Replace with schema AND p.table_name = 'YOUR_TABLE_NAME' -- Replace with table GROUP BY p.table_owner, p.table_name, p.partition_name, p.high_value ORDER BY p.partition_position;
==============
v_ts_count NUMBER;
v_job_name VARCHAR2(100) := 'DROP_TABLESPACES_JOB_' || TO_CHAR(SYSDATE, 'YYYYMMDD_HH24MISS');
BEGIN
-- Step 1: Verify the count of tablespaces to drop
SELECT COUNT(*)
INTO v_ts_count
FROM dba_tablespaces
WHERE tablespace_name NOT IN ('RDSADMIN', 'RDS_SQL_TS', 'RDS-TEMP_SQLT_TS',
'SYSAUX', 'SYSTEM', 'TEMP', 'UNDO_T1', 'USERS');
IF v_ts_count != 12 THEN
RAISE_APPLICATION_ERROR(-20001, 'Expected 12 tablespaces to drop, but found ' || v_ts_count);
END IF;
-- Step 2: Create a logging table if it doesn't exist
BEGIN
EXECUTE IMMEDIATE '
CREATE TABLE drop_ts_log (
log_id NUMBER GENERATED ALWAYS AS IDENTITY,
tablespace_name VARCHAR2(128),
status VARCHAR2(20),
message VARCHAR2(4000),
log_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT pk_drop_ts_log PRIMARY KEY (log_id)
)';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -955 THEN NULL; -- Table already exists
ELSE RAISE;
END IF;
END;
-- Step 3: Create a scheduler job to drop tablespaces
DBMS_SCHEDULER.CREATE_JOB(
job_name => v_job_name,
job_type => 'PLSQL_BLOCK',
job_action => q'[
DECLARE
v_sql VARCHAR2(4000);
BEGIN
-- Log start of job
INSERT INTO drop_ts_log (tablespace_name, status, message)
VALUES ('NONE', 'START', 'Starting tablespace drop job');
-- Loop through tablespaces to drop
FOR ts IN (
SELECT tablespace_name
FROM dba_tablespaces
WHERE tablespace_name NOT IN ('RDSADMIN', 'RDS_SQL_TS', 'RDS-TEMP_SQLT_TS',
'SYSAUX', 'SYSTEM', 'TEMP', 'UNDO_T1', 'USERS')
) LOOP
BEGIN
v_sql := 'DROP TABLESPACE ' || DBMS_ASSERT.SQL_OBJECT_NAME(ts.tablespace_name) ||
' INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS';
EXECUTE IMMEDIATE v_sql;
INSERT INTO drop_ts_log (tablespace_name, status, message)
VALUES (ts.tablespace_name, 'SUCCESS', 'Tablespace dropped successfully');
EXCEPTION
WHEN OTHERS THEN
INSERT INTO drop_ts_log (tablespace_name, status, message)
VALUES (ts.tablespace_name, 'ERROR', 'Failed to drop: ' || SQLERRM);
END;
END LOOP;
-- Log completion
INSERT INTO drop_ts_log (tablespace_name, status, message)
VALUES ('NONE', 'COMPLETED', 'Tablespace drop job completed');
COMMIT;
EXCEPTION
WHEN OTHERS THEN
INSERT INTO drop_ts_log (tablespace_name, status, message)
VALUES ('NONE', 'ERROR', 'Job failed: ' || SQLERRM);
COMMIT;
RAISE;
END;
]',
start_date => SYSTIMESTAMP,
enabled => TRUE,
auto_drop => TRUE,
comments => 'Job to drop all non-system tablespaces except specified ones'
);
-- Log job submission
INSERT INTO drop_ts_log (tablespace_name, status, message)
VALUES ('NONE', 'SUBMITTED', 'Job ' || v_job_name || ' submitted successfully');
COMMIT;
DBMS_OUTPUT.PUT_LINE('Job ' || v_job_name || ' submitted. Check drop_ts_log table for progress.');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
RAISE;
END;
/
Wednesday, September 24, 2025
index_check
WITH index_build_data AS (
SELECT DISTINCT owner, index_name, table_name, column_names, index_type, uniqueness
FROM index_build
WHERE build_status = 'NEED_BUILD' -- Adjust if you want all rows
AND index_type = 'NORMAL' -- Per your procedure
),
dba_index_data AS (
SELECT di.owner, di.index_name, di.table_name, di.index_type, di.uniqueness,
LISTAGG(dic.column_name, ',') WITHIN GROUP (ORDER BY dic.column_position) AS dba_column_names
FROM dba_indexes di
LEFT JOIN dba_ind_columns dic
ON di.owner = dic.index_owner AND di.index_name = dic.index_name
WHERE di.index_type = 'NORMAL' -- Match your procedure
GROUP BY di.owner, di.index_name, di.table_name, di.index_type, di.uniqueness
),
comparison AS (
SELECT
COALESCE(ib.owner, di.owner) AS owner,
COALESCE(ib.index_name, di.index_name) AS index_name,
ib.table_name AS ib_table_name,
di.table_name AS dba_table_name,
ib.column_names AS ib_column_names,
di.dba_column_names AS dba_column_names,
ib.index_type AS ib_index_type,
di.index_type AS dba_index_type,
ib.uniqueness AS ib_uniqueness,
di.uniqueness AS dba_uniqueness,
CASE
WHEN ib.index_name IS NULL AND di.index_name IS NOT NULL THEN 'Missing in index_build (present in source DBA_INDEXES)'
WHEN ib.index_name IS NOT NULL AND di.index_name IS NULL THEN 'Extra in index_build (missing in source DBA_INDEXES)'
WHEN ib.table_name != di.table_name THEN 'Table name mismatch'
WHEN ib.index_type != di.index_type THEN 'Index type mismatch'
WHEN ib.uniqueness != di.uniqueness THEN 'Uniqueness mismatch'
WHEN NVL(ib.column_names, 'NULL') != NVL(di.dba_column_names, 'NULL') THEN 'Column names mismatch'
ELSE 'Match'
END AS mismatch_reason
FROM index_build_data ib
FULL OUTER JOIN dba_index_data di
ON ib.owner = di.owner AND ib.index_name = di.index_name
)
SELECT
owner,
index_name,
ib_table_name,
dba_table_name,
ib_column_names,
dba_column_names,
ib_index_type,
dba_index_type,
ib_uniqueness,
dba_uniqueness,
mismatch_reason
FROM comparison
WHERE mismatch_reason != 'Match'
ORDER BY owner, index_name;
Tuesday, September 23, 2025
tbl
Monday, September 22, 2025
table count
recheck
Handling Issues Found in Checks
- If Query 2 shows missing mappings:
- Add the missing old_tablespace → new_tablespace pairs to ts_mappings:sql
INSERT INTO ts_mappings (old_tablespace, new_tablespace) VALUES ('OLD_TBS_NAME', 'NEW_TBS_NAME'); - Alternatively, exclude those indexes from rebuilding by updating their status:sql
UPDATE index_build SET build_status = 'skipped_no_mapping', error_message = 'No tablespace mapping available' WHERE tablespace_name NOT IN (SELECT old_tablespace FROM ts_mappings) AND build_status = 'need_build';
- Add the missing old_tablespace → new_tablespace pairs to ts_mappings:
- If Query 3 shows incorrect new tablespaces:
- Update ts_mappings to correct the new_tablespace values:sql
UPDATE ts_mappings SET new_tablespace = 'CORRECT_TBS_NAME' WHERE old_tablespace = 'OLD_TBS_NAME';
- Update ts_mappings to correct the new_tablespace values:
- If Query 4 shows many errors:
- Investigate why so many index_build rows lack mappings. It could indicate incomplete ts_mappings data or that some indexes don’t need tablespace changes (in which case, you might adjust the MERGE to skip them).
Step 5: Next Steps After MERGE
After the MERGE, you can proceed with the validation against DBA_INDEXES and DBA_IND_COLUMNS (as in the original response) to ensure index definitions match the database before rebuilding. Here’s a quick recap of that step:
-- Example validation (simplified; see original response for full PL/SQL)
SELECT ib.index_name, ib.table_name, ib.column_names, di.index_type, di.uniqueness
FROM index_build ib
JOIN DBA_INDEXES di ON ib.owner = di.owner AND ib.index_name = di.index_name
WHERE ib.build_status = 'need_build';Additional Notes
- Why need_build?: The condition ensures you’re only updating tablespaces for indexes flagged for DMS-related rebuilds. If you want to check/update all rows in index_build (not just need_build), remove the AND ib.build_status = 'need_build' condition from the MERGE’s ON clause and the UPDATE for clearing errors.
- Test First: Run the mapping checks and MERGE on a small subset (e.g., add WHERE ROWNUM <= 10 to queries) in a test environment to confirm behavior.
- DMS Context: If need_build isn’t the right filter or you have a different flag (e.g., dms_job IS NOT NULL), let me know, and I can adjust the queries.
If you want to see sample output from the mapping checks or need help fixing specific issues (e.g., missing mappings), share the results of the above queries or more details about your DMS process, and I’ll tailor the solution further!
-- Update matched rows UPDATE index_build ib SET ib.tablespace_name = (SELECT tsm.new_tablespace FROM ts_mappings tsm WHERE tsm.old_tablespace = ib.tablespace_name), ib.error_message = NULL WHERE ib.build_status = 'need_build' AND EXISTS (SELECT 1 FROM ts_mappings tsm WHERE tsm.old_tablespace = ib.tablespace_name); -- Update non-matched rows UPDATE index_build ib SET ib.build_status = 'error_no_mapping', ib.error_message = 'No mapping found for old tablespace: ' || ib.tablespace_name WHERE ib.build_status = 'need_build' AND NOT EXISTS (SELECT 1 FROM ts_mappings tsm WHERE tsm.old_tablespace = ib.tablespace_name); COMMIT;
-- Verify index_build against DBA_INDEXES and DBA_IND_COLUMNS WITH index_build_data AS ( SELECT owner, index_name, table_name, column_names, index_type, uniqueness, partitioned, degree, ini_trans, pct_free, build_status, error_message FROM index_build WHERE build_status = 'need_build' -- Adjust if you want all rows ), dba_index_data AS ( SELECT di.owner, di.index_name, di.table_name, di.index_type, di.uniqueness, di.partitioned, di.degree, di.ini_trans, di.pct_free, LISTAGG(dic.column_name, ',') WITHIN GROUP (ORDER BY dic.column_position) AS dba_column_names FROM dba_indexes di LEFT JOIN dba_ind_columns dic ON di.owner = dic.index_owner AND di.index_name = dic.index_name GROUP BY di.owner, di.index_name, di.table_name, di.index_type, di.uniqueness, di.partitioned, di.degree, di.ini_trans, di.pct_free ), comparison AS ( SELECT ib.owner, ib.index_name, ib.table_name, ib.build_status, -- Compare attributes and build error messages CASE WHEN ib.index_name IS NULL OR di.index_name IS NULL THEN 'Index not found in DBA_INDEXES' WHEN ib.table_name != di.table_name THEN 'Table name mismatch: index_build=' || ib.table_name || ', DBA=' || di.table_name WHEN ib.index_type != di.index_type THEN 'Index type mismatch: index_build=' || ib.index_type || ', DBA=' || di.index_type WHEN ib.uniqueness != di.uniqueness THEN 'Uniqueness mismatch: index_build=' || ib.uniqueness || ', DBA=' || di.uniqueness WHEN ib.partitioned != di.partitioned THEN 'Partitioned mismatch: index_build=' || ib.partitioned || ', DBA=' || di.partitioned WHEN ib.degree != di.degree THEN 'Degree mismatch: index_build=' || ib.degree || ', DBA=' || di.degree WHEN ib.ini_trans != di.ini_trans THEN 'Ini_trans mismatch: index_build=' || ib.ini_trans || ', DBA=' || di.ini_trans WHEN ib.pct_free != di.pct_free THEN 'Pct_free mismatch: index_build=' || ib.pct_free || ', DBA=' || di.pct_free WHEN ib.column_names != di.dba_column_names THEN 'Column names mismatch: index_build=' || ib.column_names || ', DBA=' || di.dba_column_names ELSE NULL END AS mismatch_reason, ib.column_names AS ib_column_names, di.dba_column_names AS dba_column_names, ib.index_type AS ib_index_type, di.index_type AS dba_index_type, ib.uniqueness AS ib_uniqueness, di.uniqueness AS dba_uniqueness, ib.partitioned AS ib_partitioned, di.partitioned AS dba_partitioned, ib.degree AS ib_degree, di.degree AS dba_degree, ib.ini_trans AS ib_ini_trans, di.ini_trans AS dba_ini_trans, ib.pct_free AS ib_pct_free, di.pct_free AS dba_pct_free FROM index_build_data ib FULL OUTER JOIN dba_index_data di ON ib.owner = di.owner AND ib.index_name = di.index_name ) SELECT owner, index_name, table_name, build_status, mismatch_reason, ib_column_names, dba_column_names, ib_index_type, dba_index_type, ib_uniqueness, dba_uniqueness, ib_partitioned, dba_partitioned, ib_degree, dba_degree, ib_ini_trans, dba_ini_trans, ib_pct_free, dba_pct_free FROM comparison WHERE mismatch_reason IS NOT NULL ORDER BY owner, index_name;