2012-09-11 14 views
6

ich ein Orakel 11 Tabelle mit Intervall Partitionierung und Liste bin mit wie diese Partitionen (vereinfacht):Oracle: wie eine Subpartition einer bestimmten Partition fallen

CREATE TABLE LOG 
(
    ID NUMBER(15, 0) NOT NULL PRIMARY KEY 
, MSG_TIME DATE NOT NULL 
, MSG_NR VARCHAR2(16 BYTE) 
) PARTITION BY RANGE (MSG_TIME) INTERVAL (NUMTOYMINTERVAL (1,'MONTH')) 
    SUBPARTITION BY LIST (MSG_NR) 
    SUBPARTITION TEMPLATE (
    SUBPARTITION login VALUES ('FOO') 
    , SUBPARTITION others VALUES (DEFAULT) 
    ) 
    (PARTITION oldvalues VALUES LESS THAN (TO_DATE('01-01-2010','DD-MM-YYYY'))); 

Wie ich eine bestimmte subpartitition für einen bestimmten fallen lassen Monat, ohne den (systemgenerierten) Namen der Unterpartition zu kennen? Es gibt eine Syntax "alter table ... drop subpartition for (subpartition_key_value , ...)", aber ich sehe keine Möglichkeit, den Monat anzugeben, für den ich die Unterpartition lösche. Die partition administration guide gibt auch keine Beispiele. 8-}

Antwort

3

Wie sich herausstellt, die „Subpartition für“ Syntax tut tatsächlich funktioniert, obwohl das ein Geheimnis Oracle zu sein scheint, will nicht um Dir von ... zu erzählen. Dieses :-)

ALTER TABLE TB_LOG_MESSAGE DROP SUBPARTITION FOR 
     (TO_DATE('01.02.2010','DD.MM.YYYY'), 'FOO') 

löscht die Subpartition die MSG_TIME 2010.02.01 und MSG_NR FOO enthalten würde. (Es ist nicht notwendig, dass es eine tatsächliche Zeile mit genau diesem MSG_TIME und MSG_NR gibt. Es gibt einen Fehler, wenn es keine solche Unterpartition gibt.)

+3

Wenn Sie nach "drop subpartition for" suchen, finden Sie tatsächlich eine Patentanmeldung, die diese Syntax abdeckt. 8 - {} Können Softwarepatente noch bösartiger werden? http://www.patentstorm.us/applications/20080313133/description.html –

+0

Es wurde 2013 http://www.google.com/patents/US8356014 veröffentlicht (neuer Link, da ich nichts in hstoerrs Link sehen kann) – jmsu

3

Sie die Metadaten-Tabellen verwenden, können die spezifische Subpartition Namen zu bekommen:

SQL> insert into log values (1, sysdate, 'FOO'); 

1 row(s) inserted. 

SQL> SELECT p.partition_name, s.subpartition_name, p.high_value, s.high_value 
    2 FROM user_tab_partitions p 
    3   JOIN 
    4   user_tab_subpartitions s 
    5   ON s.table_name = p.table_name 
    6  AND s.partition_name = p.partition_name 
    7  AND p.table_name = 'LOG'; 

PARTITION_NAME SUBPARTITION_NAME HIGH_VALUE HIGH_VALUE 
--------------- ------------------ ------------ ---------- 
OLDVALUES  OLDVALUES_OTHERS 2010-01-01 DEFAULT 
OLDVALUES  OLDVALUES_LOGIN 2010-01-01 'FOO' 
SYS_P469754  SYS_SUBP469753  2012-10-01 DEFAULT 
SYS_P469754  SYS_SUBP469752  2012-10-01 'FOO' 

SQL> alter table log drop subpartition SYS_SUBP469752; 

Table altered. 

Wenn Sie eine Partition dynamisch fallen wollen, kann es schwierig sein, es mit der ALL_TAB_SUBPARTITIONS Ansicht, weil die HIGH_VALUE zu finden Spalte kann nicht einfach abgefragt werden. In diesem Fall könnten Sie DBMS_ROWID verwenden, um die Subpartition object_id einer bestimmten Zeile zu finden:

SQL> insert into log values (4, sysdate, 'FOO'); 

1 row(s) inserted. 

SQL> DECLARE 
    2  l_rowid_in   ROWID; 
    3  l_rowid_type  NUMBER; 
    4  l_object_number NUMBER; 
    5  l_relative_fno  NUMBER; 
    6  l_block_number  NUMBER; 
    7  l_row_number  NUMBER; 
    8 BEGIN 
    9  SELECT rowid INTO l_rowid_in FROM log WHERE id = 4; 
10  dbms_rowid.rowid_info(rowid_in  =>l_rowid_in  , 
11       rowid_type  =>l_rowid_type , 
12       object_number =>l_object_number, 
13       relative_fno =>l_relative_fno , 
14       block_number =>l_block_number , 
15       row_number  =>l_row_number ); 
16  dbms_output.put_line('object_number ='||l_object_number); 
17 END; 
18/

object_number =15838049 

SQL> select object_name, subobject_name, object_type 
    2 from all_objects where object_id = '15838049'; 

OBJECT_NAME  SUBOBJECT_NAME OBJECT_TYPE 
--------------- --------------- ------------------ 
LOG    SYS_SUBP469757 TABLE SUBPARTITION 
1

Danke für den Beitrag - es war sehr nützlich für mich.

Eine Beobachtung, obwohl auf dem obigen Skript, um die Partition zu identifizieren und löschen:

Die object_id zurück von dbms_rowid.rowid_info ist nicht die object_id der all_objects Tabelle. Es ist eigentlich die data_object_id. Es wird beobachtet, dass diese IDs normalerweise übereinstimmen. Nach dem mehrfachen Abschneiden der partitionierten Tabelle divergierten diese IDs jedoch in meiner Datenbank. Daher kann es sinnvoll sein, um stattdessen die data_object_id zu verwenden, um den Namen der Partition herauszufinden:

select object_name, subobject_name, object_type 
from all_objects where data_object_id = '15838049'; 

From the table description of ALL_OBJECTS: 

OBJECT_ID Objektnummer des Objekts DATA_OBJECT_ID Objektnummer des Segments, welches das Objekt enthält

http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_rowid.htm

In dem Beispielcode, der in dem obigen Link bereitgestellt wird, wird stattdessen DBMS_ROWID.ROWID_OBJECT(row_id) verwandt, um dieselbe Information abzuleiten, die von dbms_rowid.rowid_info gegeben wird. In der Dokumentation zu diesem Beispiel wird jedoch erwähnt, dass es sich um eine Datenobjektnummer aus der ROWID handelt.

Beispiele

diesem Beispiel wird die ROWID für eine Zeile in der EMP Tabelle zurückgibt, extrahiert die Datenobjektnummer von dem ROWID, die ROWID_OBJECT Funktion im DBMS_ROWID Paket verwendet wird, zeigt dann die Objektnummer:

DECLARE object_no INTEGER; row_id ROWID; ...BEGIN
SELECT ROWID IN row_id VON emp WHERE empno = 7499; object_no: = DBMS_ROWID.ROWID_OBJECT (row_id); DBMS_OUTPUT.PUT_LINE ('Die Obj. # Ist ' || object_no); ...