sql >> Databasteknik >  >> RDS >> Oracle

Kontroll av att hoppa över intervallpartition

Utan förklaringsplanen eller tabelldefinitionen är det verkligen svårt att säga vad som händer. Min första gissning är att du har LOKALA partitionerade index utan year kolumn. De hjälper till med COUNT(*) på en partition, men de verkar inte användas när du frågar ett enda år (åtminstone 10.2.0.3).

Här är ett litet exempel som återger ditt fynd (och en lösning):

SQL> CREATE TABLE DATA (
  2     YEAR NUMBER NOT NULL,
  3     ID NUMBER NOT NULL,
  4     extra CHAR(1000)
  5  ) PARTITION BY RANGE (YEAR) (
  6     PARTITION part1 VALUES LESS THAN (2010),
  7     PARTITION part2 VALUES LESS THAN (2011)
  8  );
Table created

SQL> CREATE INDEX ix_id ON DATA  (ID) LOCAL;
Index created

SQL> INSERT INTO DATA 
  2  (SELECT 2009+MOD(ROWNUM, 2), ROWNUM, 'A' FROM DUAL CONNECT BY LEVEL <=1e4);

10000 rows inserted

SQL> EXEC dbms_stats.gather_table_stats(USER, 'DATA', CASCADE=>TRUE);

PL/SQL procedure successfully completed

Jämför nu de två förklara planerna:

SQL> SELECT COUNT(*) FROM DATA WHERE YEAR=2010;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=197 Card=1 Bytes=4)
   1    0   SORT (AGGREGATE)
   2    1     PARTITION RANGE (SINGLE) (Cost=197 Card=5000 Bytes=20000)
   3    2       TABLE ACCESS (FULL) OF 'DATA' (TABLE) (Cost=197 Card=5000...)

SQL> SELECT COUNT(*) FROM DATA PARTITION (part1);

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=11 Card=1)
   1    0   SORT (AGGREGATE)
   2    1     PARTITION RANGE (SINGLE) (Cost=11 Card=5000)
   3    2       INDEX (FULL SCAN) OF 'IX_ID' (INDEX) (Cost=11 Card=5000)

Som du kan se är indexet inte används när du frågar året direkt. När du lägger till årtalet till LOCAL-indexet kommer det att användas. Jag använde COMPRESS 1-instruktionen för att berätta för Oracle att komprimera den första kolumnen. Det resulterande indexet är nästan lika stort som det ursprungliga indexet (tack vare komprimeringen) så prestandan bör inte påverkas.

SQL> DROP INDEX ix_id;
 Index dropped

SQL> CREATE INDEX ix_id ON DATA (year, ID) LOCAL COMPRESS 1;
Index created

SQL> SELECT COUNT(*) FROM DATA WHERE YEAR=2010;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=12 Card=1 Bytes=4)
   1    0   SORT (AGGREGATE)
   2    1     PARTITION RANGE (SINGLE) (Cost=12 Card=5000 Bytes=20000)
   3    2       INDEX (RANGE SCAN) OF 'IX_ID' (INDEX) (Cost=12 Card=5000...)


  1. Få PHP MYSQL-rankningsfrågan att rangordna baserat på totalsumman av poäng

  2. PK bruten i oracle sql

  3. Hur kör man en MYSQL-fråga på en fördefinierad fast tid?

  4. Tilldela dynamiskt alias till alla fältnamn i msyql-frågan