Hi,
Below is a table definition from a Oracle 11g instance (sorry for the long text).
CREATE TABLE "SCHEMA"."DOCUMENTS"
( "AA" NUMBER(10,0) NOT NULL ENABLE,
"ACC_YEAR" NUMBER(4,0) NOT NULL ENABLE,
"IN_DAY" DATE,
"DOC_NUMBER" VARCHAR2(50 BYTE),
"DOC_DATE" DATE,
"IN_PLACEOFCREATION" VARCHAR2(500 BYTE),
"IN_PERSON" VARCHAR2(500 BYTE),
"WORKER" VARCHAR2(50 BYTE),
"IN_DESCRIPTION" VARCHAR2(1000 BYTE),
"IN_RECEIVER" VARCHAR2(400 BYTE),
"IN_FORWARD" VARCHAR2(400 BYTE),
"ARCHIVE" VARCHAR2(250 BYTE),
"OUT_DAY" DATE,
"OUT_PLACEOFCREATION" VARCHAR2(500 BYTE),
"OUT_AUTHORITY" VARCHAR2(500 BYTE),
"OUT_DESTINATION" VARCHAR2(500 BYTE),
"OUT_DESCRIPTION" VARCHAR2(1000 BYTE),
"OUT_ANNOUNCE" VARCHAR2(500 BYTE),
"FAKELOS_AA" NUMBER(10,0),
"FAKELOS_DATE" DATE,
"ARCHIVE_DATE" DATE,
"SEND_TYPE" VARCHAR2(50 BYTE),
"COMMENTS" VARCHAR2(4000 BYTE),
"FAKELOS_YEAR" NUMBER(10,0),
"IN_PERSON_CODE" VARCHAR2(20 BYTE),
"DOC_PIN" VARCHAR2(10 BYTE),
"DOC_STATUS" VARCHAR2(50 BYTE),
"DOC_EXPIREDATE" DATE,
"DOC_RECEIVE_TYPE" VARCHAR2(50 BYTE),
"V_USAGE" VARCHAR2(20 BYTE) NOT NULL ENABLE,
"V_OLD_USAGE" VARCHAR2(20 BYTE) DEFAULT '',
"N_OLD_YEAR" NUMBER(4,0),
"N_OLD_AA" NUMBER(10,0),
"V_PRIORITY" VARCHAR2(50 BYTE) DEFAULT '',
"V_SCALING" VARCHAR2(50 BYTE) DEFAULT '',
"V_MASTERUSAGE" VARCHAR2(20 BYTE),
"N_MASTERYEAR" NUMBER(4,0),
"N_MASTERAA" NUMBER(10,0),
"DOC_DESTROYDATE" DATE,
"N_PAGECOUNT" NUMBER(10,0),
"V_BARCODE" VARCHAR2(50 BYTE),
"V_APPLITYPE" VARCHAR2(64 BYTE),
"V_BARCODE_OUT" VARCHAR2(50 BYTE),
"V_TEAM" VARCHAR2(200 BYTE),
"V_EMAIL" VARCHAR2(100 BYTE),
"V_MOBILEPHONE" VARCHAR2(30 BYTE),
"N_STATUSID" NUMBER(10,0),
"V_ORGANIZATION" VARCHAR2(200 BYTE),
"V_UNIT" VARCHAR2(200 BYTE),
"V_IN_SUBJECT_CHAR" VARCHAR2(200 BYTE),
"V_OUT_SUBJECT_CHAR" VARCHAR2(200 BYTE),
"V_IMPORT_COODE" VARCHAR2(200 BYTE),
"V_WRITER" VARCHAR2(200 BYTE),
"V_UNDERSIGNED" VARCHAR2(200 BYTE),
"UPDATE_STRING" VARCHAR2(200 BYTE),
"CREATED_BY" VARCHAR2(200 BYTE),
"UPDATED_BY" VARCHAR2(200 BYTE),
"CREATED_ON" DATE,
"UPDATED_ON" DATE,
"N_CANCELLED" NUMBER(1,0),
"FAKELOS_AA2" VARCHAR2(16 BYTE),
"N_IN_PERSON_PUBLICBODY_ID" NUMBER(10,0),
"N_OUT_DEST_PUBLICBODY_ID" NUMBER(10,0),
"N_OUT_ANNOUNCE_PUBLICBODY_ID" NUMBER(10,0),
"N_DOCUMENTRECEIVED" NUMBER(1,0),
"N_ANNOUNCEMENTRECEIVED" NUMBER(1,0),
"N_WEB_RAISED" NUMBER(1,0),
"V_WEB_RAISEDNO" VARCHAR2(30 BYTE),
"N_EXCLUDE_MASTER_UPDATE" NUMBER(1,0),
"N_EMPLOYEEID" NUMBER(10,0),
"N_TOPAA" NUMBER(10,0),
"N_TOPYEAR" NUMBER(4,0),
"V_TOPUSAGE" VARCHAR2(20 BYTE),
"V_DOCUMENTDESCR" VARCHAR2(300 BYTE),
"V_COPYDOCUMENT" VARCHAR2(100 BYTE),
CONSTRAINT "DOCUMENTS_PKEY" PRIMARY KEY ("V_USAGE", "ACC_YEAR", "AA")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 655360 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT
FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "TS_PROTOCOL" ENABLE,
CONSTRAINT "DOCUMENTS_STATUS_FKEY" FOREIGN KEY ("N_STATUSID")
REFERENCES "SCHEMA"."STATUS" ("N_ID") ENABLE,
CONSTRAINT "FK_DOCUMENTS_EMPLOYEES" FOREIGN KEY ("N_EMPLOYEEID")
REFERENCES "SCHEMA"."EMPLOYEE" ("N_ID") ON DELETE SET NULL ENABLE
) SEGMENT CREATION IMMEDIATE
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
STORAGE(INITIAL 4194304 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT
FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "TS_PROTOCOL" ;
CREATE INDEX "SCHEMA"."DOUBLE_RECORDS_CHECK" ON "SCHEMA"."DOCUMENTS"
("IN_PERSON", "DOC_NUMBER", "DOC_DATE")
PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT
FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "TS_GENERAL" ;
CREATE INDEX "SCHEMA"."IDX_ACCYEAR" ON "SCHEMA"."DOCUMENTS" ("ACC_YEAR")
PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT
FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "TS_GENERAL" ;
CREATE INDEX "SCHEMA"."IDX_CREATEDBY" ON "SCHEMA"."DOCUMENTS" ("CREATED_BY")
PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT
FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "TS_GENERAL" ;
CREATE INDEX "SCHEMA"."IDX_INDAY" ON "SCHEMA"."DOCUMENTS" ("IN_DAY")
PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT
FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "TS_GENERAL" ;
CREATE INDEX "SCHEMA"."IDX_MASTERUSAGEYEAR" ON "SCHEMA"."DOCUMENTS"
("V_MASTERUSAGE", "N_MASTERYEAR")
PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT
FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "TS_GENERAL" ;
CREATE INDEX "SCHEMA"."IDX_NMASTERAA" ON "SCHEMA"."DOCUMENTS" ("N_MASTERAA")
PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT
FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "TS_GENERAL" ;
CREATE INDEX "SCHEMA"."IDX_UPDATED_BY" ON "SCHEMA"."DOCUMENTS" ("UPDATED_BY")
PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT
FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "TS_GENERAL" ;
CREATE INDEX "SCHEMA"."IDX_UPDATED_ON" ON "SCHEMA"."DOCUMENTS" ("UPDATED_ON")
PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT
FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "TS_GENERAL" ;
CREATE INDEX "SCHEMA"."INDAY_USAGE" ON "SCHEMA"."DOCUMENTS" ("IN_DAY",
"V_USAGE")
PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT
FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "TS_GENERAL" ;
CREATE UNIQUE INDEX "SCHEMA"."UNIQUERECORDS_INDEX" ON "SCHEMA"."DOCUMENTS"
("V_DOCUMENTDESCR")
PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT
FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "TS_GENERAL" ;
The following query:
SELECT COUNT(*) FROM DOCUMENTS WHERE V_USAGE='ANAT' AND ACC_YEAR=2013 AND
CREATED_ON>=TO_DATE('01/11/2013', 'DS') AND CREATED_BY='user';
generates this plan, which is normal I guess, since there's no index for the CREATED_ON column.
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 798 (1)| 00:00:10 |
| 1 | SORT AGGREGATE | | 1 | 26 | | |
|* 2 | TABLE ACCESS BY INDEX ROWID| DOCUMENTS | 1 | 26 | 798 (1)| 00:00:10 |
|* 3 | INDEX RANGE SCAN | IDX_CREATEDBY | 2131 | | 11 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("CREATED_ON">=TO_DATE(' 2013-11-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')
AND "V_USAGE"='ANAT' AND "ACC_YEAR"=2013)
3 - access("CREATED_BY"='user')
If I create an index for the CREATED_ON column, the generated plan is:
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 351 (0)| 00:00:05 |
| 1 | SORT AGGREGATE | | 1 | 26 | | |
|* 2 | TABLE ACCESS BY INDEX ROWID| DOCUMENTS | 1 | 26 | 351 (0)| 00:00:05 |
|* 3 | INDEX RANGE SCAN | IDX_CREATED_ON | 3809 | | 13 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("CREATED_BY"='user' AND "V_USAGE"='ANAT' AND "ACC_YEAR"=2013)
3 - access("CREATED_ON">=TO_DATE(' 2013-11-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
This seems a bit strange, since the rows returned by the IDX_CREATED_ON index are 3809 (more than the no index solution), but the CPU cost is less than the first case.
If I create an index on both CREATED_ON and CREATED_BY, the plan is:
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 4 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 26 | | |
|* 2 | TABLE ACCESS BY INDEX ROWID| DOCUMENTS | 1 | 26 | 4 (0)| 00:00:01 |
|* 3 | INDEX SKIP SCAN | IDX_CREATED_ON_BY | 2 | | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("V_USAGE"='ANAT' AND "ACC_YEAR"=2013)
3 - access("CREATED_ON">=TO_DATE(' 2013-11-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"CREATED_BY"='user' AND "CREATED_ON" IS NOT NULL)
filter("CREATED_BY"='user')
I suppose the last solution seems to be the best, seeing the cost in CPU and number of rows returned from the intermediate results. Forgot to mention this query returns 23.
So, the big question is: Could you think of a better index that fits this specific query?