I am a SQL guy, but am doing a stint in ORACLE land. Nothing wrong w/ expanding one's boundaries....
I have been given a view to a table. I do have permission to delete from that view.
Delete from vwGregsViewOnTable where SEQ = 12345
this takes 12 minutes. There are ~20M rows in the table, but 12 minutes?
I got a DBA involved and they confirmed that I am doing a table scan.
We scripted the table and that follows here in part...
CREATE TABLE SYT_SYALERTQUEUE
(
IDRECMAIN VARCHAR2(32 BYTE),
IDRECPARENT VARCHAR2(32 BYTE),
IDREC VARCHAR2(32 BYTE),
SEQ NUMBER(10),
.
.
.
CREATE INDEX SYNDX00000000000000000002277 ON SYT_SYALERTQUEUE
(SEQ)
LOGGING
TABLESPACE WV90NDX
It does appear that there is an index on the column I was told I should use.
in this case, vwGregsViewOnTable is the view on SYT_SYALERTQUEUE
My question is - how can I coax ORACLE into using the index. It doesnt seem to want to by default.
To answer your question: You can force the Oracle's SQL-optimizer to use a certain index:
SELECT /*+ INDEX (table indexname)*/ col1, col2
FROM table
WHERE blabla ;
This thingie here /*+ INDEX (table indexname)*/ is called an optimizer-hint. Most of the time its not really wise to use that.
Related
I am going to develop a reporting database by querying the production database once using a stored procedure.
The stored procedure will then write the result into it's own output tables.
Following is the schema for the output table:
Create table Output (
Customer_ID NUMBER(15) not null,
STD_HASH RAW(1000 BYTE) ,
VALID_PERIOD_START NOT NULL TIMESTAMP(6),
VALID_PERIOD_END NOT NULL TIMESTAMP(6),
Address VARCHAR2(30 CHAR),
period for valid_period(valid_period_start,valid_period_end),
Constraint Output_PK Primary Key ( Customer_ID, valid_period_start, valid_period_end )
)
As the stored procedure will perform a lot of update and delete statement on the output table, and those output table is very big. The largest one I have right now is 8GB. I am thinking to alter those output tables with the "SHRINK SPACE" option at the end of the stored procedure to reclaim some spaces.
Following is the statement that I am going to apply:
Alter table OUTPUT1 ENABLE ROW MOVEMENT; -- Temporary enable row movement for the table
Alter TABLE output2 SHRINK SPACE;
Alter table OUTPUT1 DISABLE ROW MOVEMENT;-- Disable row movement.
Those output tables are temporal table that is using the valid period and the ID from production as a primary key.
However, as I am very new with the Shrink Space function. Can anyone tell me what is the disadvantage of using this function?
The table, basically will not be updated from anywhere other than this stored procedure. The stored procedure will be scheduled to run in a daily base.
Thanks in advance!
yes, shrink has some restrictions:
(1) it locks the table during the shrink operation
(2) it change the rowid of the table.
(3) it needs the tablespace with automatic segment-space management enabled.
we have other alternatives to claim the unused space:
(1) export/import
(2) dbms_redefinition
I got to know as we cannot convert existing non-partitioned table to partitioned table but the below link from the Oracle suggest that with the help of "ONLINE" keyword we can do it.
https://docs.oracle.com/en/database/oracle/oracle-database/12.2/vldbg/evolve-nopartition-table.html#GUID-5FDB7D59-DD05-40E4-8AB4-AF82EA0D0FE5
CREATE TABLE my_tab ( a NUMBER(38,0), b NUMBER(38,0));
ALTER TABLE MY_TAB MODIFY PARTITION BY RANGE (a) INTERVAL (1000) (
PARTITION p1 VALUES LESS THAN (1000)) ONLINE;
But it's not working for me, throwing error as "Invalid Partition Name".
I don't want to use dbms_redefinition.
If you are using Oracle 12c Release 2 you could use single ALTER to convert non-partitioned table to partitioned one :
CREATE TABLE my_tab ( a NUMBER(38,0), b NUMBER(38,0));
ALTER TABLE MY_TAB MODIFY PARTITION BY RANGE (a) INTERVAL (1000) (
PARTITION p1 VALUES LESS THAN (1000)) ONLINE;
On Oracle Database 12c Release 1 (12.1.0.2.0) and without using dbms_redefinition your options may be limited to creating a new partitioned table with the same structure as the original table and copying over the data, creating indexes, constraints etc.
CREATE TABLE my_tab_part -- new partitioned table
PARTITION BY RANGE (a)
INTERVAL ( 1000 )
(PARTITION p1 VALUES LESS THAN (1000))
AS
SELECT * FROM my_tab;
I have the following PL/SQL code:
DROP TABLE TAB_PARAM;
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE TAB_PARAM
(
TABLE_OWNER VARCHAR2(30) NOT NULL,
TABLE_NAME VARCHAR2(30) NOT NULL,
COLUMN_NAME VARCHAR2(30) NOT NULL,
PATTERN VARCHAR2(1024),
TYPE_METHODE VARCHAR2(30) NOT NULL,
SEPARATEUR VARCHAR2(20),
ID VARCHAR2(30),
CONSTRAINT PK_TAB_PARAM PRIMARY KEY (TABLE_OWNER,TABLE_NAME,COLUMN_NAME) USING INDEX TABLESPACE IND_PARC_256M NOLOGGING
)
TABLESPACE TAB_PARC_256M NOLOGGING NOCACHE NOMONITORING NOPARALLEL';
commit;
END;
/
I don't understand the part :
CONSTRAINT PK_TAB_PARAM PRIMARY KEY (TABLE_OWNER,TABLE_NAME,COLUMN_NAME) USING INDEX TABLESPACE IND_PARC_256M NOLOGGING
Nor the part:
TABLESPACE TAB_PARC_256M NOLOGGING NOCACHE NOMONITORING NOPARALLEL';
I know that it is setting the ID as primary key of TAB_PARAM but then I do not get the index part.
Can anyone help me understand this code please?
Sometimes you can create a table in a disposable way , for example you need to read data via sqlloader from file and insert in table , after that you will select all records from table . This operation doesnt need indexes and doesnt need primary key . Anyway it is always good to create primary key when you create a table and Oracle will create index for you . You can create more indexes whenever you want since the table was created . Now suppose you wanna update the table using where condition on a field who is not a primary key , it could be a better decision create an index on that field . In addition when you create indexes or table , you can associate tablespaces (created before) and could be good practice separate tablespaces for tables and indexes . All those operations are DDL Statements . In Oracle you can check datafiles , tables and indexes with those queries select * from dba_data_files; select * from dba_tables; select * from dba_indexes;
For primary key oracle implicitly creates unique index in table's tablespace.
This part USING INDEX TABLESPACE allow us to indicate tablespace for this implicitly index.
NOLOGGING - data is modified with minimal logging (to mark new extents invalid and to record dictionary changes).
NOCACHE - Oracle doesn't store blocks in the buffer cache.
NOPARALLEL - Parallel execution is not allowed on this table.(Default value)
NOMONITORING - Disable statistics collection. Now is deprecated. There is other mechanism to collect statistic
Edit. from oracle doc
Oracle Database uses an existing index if it contains a unique set of values before enforcing the primary key constraint. The existing
index can be defined as unique or nonunique. When a DML operation is
performed, the primary key constraint is enforced using this existing
index.
If there already index hitting the pk columns , oracle will used it, else then Oracle Database generates a unique index.
so you can create a primary key in oracle without an index if there was already index for that columns , specifying an index is for performance issue. The purpose of an index in a table is to 'read' the data faster.
From the oracle document
An index is a schema object that contains an entry for each value that
appears in the indexed column(s) of the table or cluster and provides
direct, fast access to rows.
As for the TABLESPACE, its where the database object exists, so when you create a table you specify in which tablespace you want it to exists. Read more here oracle document
As for NOLOGGING NOCACHE NOMONITORING, so the table not to be logged in redo logs or cached, also related to performance issue.
I am trying to insert rows in a ErrorTable which has a few fields plus an idError which is supossed to be the primary key. I need idError to be autoincremented. However one requirement is we cannot use a trigger, so using O.AutoInc would not work for us.
We also tried to use plain sql using a sequence. However we have two blob fields which makes the query too long ( getting the string literal too long error).
Any idea about how to attack this problem? I am also considering to use UUID.
Note: we are using oracle-xe-11g
In 11g you can have only implement an auto-incrementing identifier with a trigger. So it seems your requirements rule out anything except SYS_GUID. Find out more.
" it also represents another query to get that value "
Not necessarily. If you have the option to define the target table you can set a default values for the UUID column like this:
create table t23 (
id raw(16) default sys_guid() not null primary key
, col1 varchar2(10)
);
Then
SQL> insert into t23 (col1) values ('ABC');
1 row created.
SQL> select * from t23;
ID COL1
-------------------------------- -----------
7DD7216E731C126537615FE1244B4B50 ABC
SQL>
Note: tested on 12C but should work in earlier versions.
I'm creating a database which will utilize composite partitioning. I will partition one table using range partitioning (by date)
and then further subpartition it by hash (by client id). So far so good, no problem, but I also need to have those partitions
stored in separate data files each dbf holding data for a single month. I'm reading on composite partitions and what I found
is that primary range partitioning will be only a logical one and data will be stored in subpartitions instead which seems to
make my goal impossible. Am I right and should look for a different solution?
Thanks in advance.
My databases are Oracle 11g and Oracle 12
On existing table you can move partitions or subpartitions to a different tablespace, i.e. different datafile, examples:
ALTER TABLE scuba_gear MOVE SUBPARTITION bcd_types TABLESPACE tbs23;
ALTER TABLE parts MOVE PARTITION depot2 TABLESPACE ts094;
see Moving Subpartitions and Moving Table Partitions
For new tables typically you would be create them like this:
CREATE TABLE sales
( prod_id NUMBER(6)
, cust_id NUMBER
, time_id DATE
, channel_id CHAR(1)
, promo_id NUMBER(6)
, quantity_sold NUMBER(3)
, amount_sold NUMBER(10,2)
)
PARTITION BY RANGE (time_id)
INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))
STORE IN (ts_1, ts_2, ts_3, ts_4, ts_5, ts_6 ,ts_7 ,ts_8, ts_9, ts_10, ts_11, ts_12)
SUBPARTITION BY HASH (cust_id) SUBPARTITIONS 4
( PARTITION before_2000 VALUES LESS THAN (TO_DATE('01-JAN-2000','dd-MON-yyyy')));
Oracle then will put the monthly partitions by "round-robin" method to these 12 tablespaces. STORE IN clause is also possible for subpartitions, see Creating a composite range-hash partitioned table