High Water Mark (HWM) for a table in an Oracle Database is the line between blocks that have been used and ones that have never been. Truncating a table resets the HWM to zero.
Now, if I have a partitioned table, I'd like to know if the following is true:
Does each partition maintain its own HWM?
If not, does alter table ... drop partition ... affect table's HWM?
The idea is I'd like to populate partition's tables with insert /*+ append */ (direct path insert), but it only writes data beyond the HWM, so will the space be reused if I recreate the partition? I failed to find information on this specific aspect.
Each partition is a separate segment, so each would have its own HWM. I presume that truncating the whole table would reset the HWM for all partitions. You can truncate individual partitions as well, which certainly would reset the HWM for the partition.
In addition to Dave Costa's answer, response to second question: If you truncate the partition, the HWM will be at zero, so the space will be regained for direct path insert(space will be used). If you drop the partition, the space will be free for any other segment to be used. In particular, for your new partition.
So, in fewer words:
if you truncate the partition, space will be available for this
partition.
if you drop the partition, the space will be free and
usable for every segment in the tablespace.
Also, another trick to use if you want to reuse the space is to do an
alter table move partition. This will "recreate" the partition, without loosing the data.
There are more details, but this is your question about.
Related
I have partitioned a table that is growing almost at a rate of 7-8 million rows a day. The partitioning has been done using a timestamp column as data can be archived or discarded a few weeks later. I have also created an index on the table which are on primary key or another value that is unique. My indexes are partitioned as well, however the partioning of index has been done using a hash function and does not include the partition key of table (which is a timestamp). So I have a few questions.
The table is a write-intensive table. It is currently mostly inserts, one update per row and 2-3 lookups within seconds of creation by indexed id and then the record is never accessed for any operation.
Is it optimal to define local indexes on the unique id or is it better to define global indexes and partition them as I have already done? If I define global indexes, without table partitioning key in it (timestamp, which is not used in lookup), will the access be more expensive if the number of partitions is huge?
What are the downsides of having global partitioned indexes for constantly growing data?
Once I decide to remove the partitions at a later point of time, since the indexes are not partitioned by timestamp but instead by unique id, will the operation cause a direct impact on functioning indexes?
Any other recommendations will be helpful.
Actually I don't know any reason to make an index partition different to table partition (that's what you have).
Either make global index or local index, i.e. partitioned index where partition of index is the same as partition of underlying table.
When you have global index and you drop or truncate a partition then the global indexes becomes "unusable" and have to be rebuild. You can automatically achieve this by adding clause UPDATE INDEXES to your drop/truncate statement. However, such operation may take some time, this is the main drawback of a global index.
In general local indexes are better, they are easier to maintain and usually faster since they are smaller. However, if you have many partitions and your main queries do not include the partition key (the timestamp in your case) then local index may have a negative impact on performance. If you have let's say 100 partitions, then Oracle would have to scan 100 index partitions which basically means: Scanning 100 indexes! In such case a global index is much faster.
Today I was reading about "Partitioned index" from this link for a performance tuning requirement.
The example that is given in the link reads like the following:
CREATE INDEX employees_global_part_idx ON employees(employee_id)
GLOBAL PARTITION BY RANGE(employee_id)
(PARTITION p1 VALUES LESS THAN(5000),
PARTITION p2 VALUES LESS THAN(MAXVALUE));
Till this all looks good except it is somewhat confusing to me that during definition of this index we are manually setting value of p1 as less than 5000
So for example, if the table has 12000 records, one partition has till 1 to 5000 records and the other one has 5000 to 12000 records which are unequal to each other. Also another hurdle in this approach is one can not make more partitions later on if intended. So this indexing approach with time will not be able to give a good performance advantage.
So is there any way overcome this problem in partitioned index?
In case the employee_id values are incremented when new records are created, you may want to use a HASH partitioned index instead of RANGE partitioned.
As per Oracle Partitioning guide:
Hash partitioned global indexes can also limit the impact of index skew on monotonously increasing column values.
Your index creation query would then be:
CREATE INDEX employees_global_part_idx ON employees(employee_id) GLOBAL
PARTITION BY HASH(employee_id)
(PARTITION p1,
PARTITION p2);
This lets Oracle take care of splitting the data evenly across the available partitions.
If you really want to use RANGE partitioned index, then every now and then you would need to maintain the index, by splitting the last partition and rebuilding the index.
Read also: Global Partitioned Indexes.
In terms of partitioning Oracle provides three types of indexes:
Local Partitioned Indexes: Each table partition has a corresponding index partition. I think this type is used (and useful) by majority.
Global Non-Partitioned Indexes: The index has no partition and spans over entire table. For example, such indexes are required for unique keys where partition key is not part of the unique key.
Global Partitioned Indexes (the type you refer in your question): You define partition rule of table independently from partition rule of the index.
Actually I cannot image any situation where a "Global Partitioned Indexes" really makes sense. They would be useful only for some very special, resp. exotic use-cases. Maybe when you have really huge amount of data and you have to distribute your index over different physical storages.
I made a mistake to a production table for the table's partition upper limit, now I would like to update the table's latest partition to a smaller value. Is there a simple way to do it without off the load the data and re-create the partition with smaller upper limit value, then load the data back? Thanks much!
You could:
Split the upper partition, and drop the new highest partition
Exchange the partition with a newly created table, drop the now-empty upper partition, add a new upper partition, and exchange the table with it.
The first option would be the better one, I'd expect -- I believe that in 11g splitting a partition is optimised if the data is only going to be contained in one of the new partitions.
Oracle SQL references describes partition:
Partitioning allows a table, index, or index-organized table to be subdivided into smaller pieces, where each piece of such a database object is called a partition. Each partition has its own name, and may optionally have its own storage characteristics.
Then I have a question, if I only have one hard disk, the partition table can be placed only on a disk. Can a partition table improve performance?
Partitioning on a single disk can still help for some queries. For instance, Oracle can do partition-pruning: this is the ability to select from only a subset of all partitions for a query.
Suppose that you have a table that contains data from the last 12 months. If you want to query some total and average over one particular month, Oracle will probably need to FULL SCAN the whole table or read a lot of data with an index. With a partitioning scheme by month, Oracle would only need to read 1/12th of the data and still be able to FULL SCAN the partition as if it were a smaller version of the big table.
The tablespace in Oracle 10g is almost 100% used.
Size (MB) = 571,768.0
Used (MB) = 571,534.0
I just deleted (and committed) thousands of records in a table that belongs to a schema associated with that tablespace. Surprisingly, no space was freed up according to the Tablespaces page on Enterprise Manager.
Question: is there anything that I need to do to force Oracle to release the space corresponding to the deleted records?
The space you are seeing is for SEGMENTS on tablespace.
A Tablespace contains Segments. Each Segment is associated to an Index or a Table. Segments contains extends, and extends contains blocks. An for a table, a block contains rows.
When you delete rows on a table you are freeing the space ocuppied by rows but the space for new segments remains equal.
To free this space you can try to:
ALTER TABLESPACE xxx COALESCE;
or
ALTER TABLE xxx MOVE;
The first one, will "combine all contiguous free extents into larger contiguous extents". Depending on your configuracion, this can be executed by Oracle automatically. Also, may be it does not free to much because the location of data relative to the highwatermark on segment.
The second one "lets you relocate data of a nonpartitioned table or of a partition of a partitioned table into a new segment, optionally in a different tablespace, and optionally modify any of its storage attributes.". Be carefull with this because you need free space to achieve this, execute it against another tablespace or add more datafiles.
If you are using oracle 10g or greater, you can purge the recycle bin using command
purge recylebin
or even purge the contents related to the tablespace using
purge tablespace
This should free up the space which is deleted but not yet available , please note this would be made available automatically when the space stress occurs for the given tablespace.
In addition,
You can use the segment advisor to find all the segments that you can "shrink", and easily reclaim your space.
Read more at
Segment Shrink
And the last one you can use with locally managed tablespaces
Alter Tablespace tablespace_name shrink space
This would free as much space as possible while maintaining other attributes.
Rebuild your indexes.