Oracle 11 Index только для части данных - PullRequest
2 голосов
/ 08 октября 2011

Я использую таблицу, таблицу с именем T и столбец с именами C_I (индекс) и C_D (данные).

Теперь я хотел бы иметь только строку в индексе, если C_D = null.

CREATE INDEX T_INDEX ON T(C_I) STORAGE(BUFFER_POOL KEEP);

Как мне получить предложение WHERE C_D IS NULL в этом операторе создания?

Ответы [ 3 ]

7 голосов
/ 08 октября 2011

Позвольте мне сначала убедиться, что я правильно понимаю вопрос:

  • Вы хотите ускорить SELECT .. WHERE C_D IS NULL, но вы не хотите ускорить любой иззапросы, которые ищут ненулевой C_D.
  • Вы также хотите убедиться, что в индексе нет «ненужных» ненулевых значений, чтобы сэкономить место.

Если этопонимание правильное, тогда вам нужен функциональный индекс.I'e.индекс для функции в поле, а не само поле ...

CREATE INDEX T_IE1 ON T (CASE WHEN C_D IS NULL THEN 1 ELSE NULL END) COMPRESS

..., которое вы затем запросите как ...

SELECT * FROM T WHERE (CASE WHEN C_D IS NULL THEN 1 ELSE NULL END) = 1

... которыйэквивалентно ...

SELECT * FROM T WHERE C_D IS NULL

... но быстрее, так как он использует индекс:

enter image description here

Это экономит место, потому что индексы из одного столбца делаютне хранить NULL.Кроме того, используйте COMPRESS, поскольку индекс будет содержать только один ключ, поэтому нет необходимости тратить пространство на повторение одного и того же ключа снова и снова в структуре индекса.

ПРИМЕЧАНИЕ. В Oracle 11 вы могли бытакже создайте виртуальный столбец на основе функций (на основе приведенного выше выражения CASE), затем индексируйте и запросите этот столбец напрямую, чтобы сохранить некоторую повторяемость ввода.

-- РЕДАКТИРОВАТЬ ---

Если вы также заинтересованы в запросе C_I вместе с C_D IS NULL, вы можете ...

CREATE UNIQUE INDEX T_IE2 ON T (C_I, CASE WHEN C_D IS NULL THEN 1 ELSE NULL END)

... и запросить егос (например) ...

SELECT * FROM T WHERE C_I > 'some value' AND (CASE WHEN C_D IS NULL THEN 1 ELSE NULL END) = 1

... что эквивалентно ...

SELECT * FROM T WHERE C_I > 'some value' AND C_D IS NULL

... но быстрее, так как он использует индекс T_IE2.

Это фактически единственный индекс, который вам нужен для вашей таблицы (он «покрывает» первичный ключ, поэтому вам больше не нужен отдельный индекс только для C_I).Это также означает, что одинаковые ROWID никогда не сохраняются в более чем одном индексе, что экономит пространство.

ПРИМЕЧАНИЕ: COMPRESS больше не имеет смысла для индекса T_IE2.

-- РЕДАКТИРОВАТЬ 2 ---

Если вы заботитесь о простоте больше, чем о пространстве, вы можете просто создать составной индекс для {C_I, C_D}.Oracle хранит значения NULL в составном индексе, пока в одном кортеже есть хотя бы одно значение, отличное от NULL:

CREATE UNIQUE INDEX T_IE3 ON T (C_I, C_D)

Используется индекс:

SELECT * FROM T WHERE C_I > 1 AND C_D IS NULL

Как и в предыдущемРЕДАКТИРОВАТЬ, это единственный индекс, который вам нужен на вашем столе.

3 голосов
/ 08 октября 2011
 CREATE INDEX T_INDEX ON T ( CASE WHEN CD IS NULL THEN C_I ELSE NULL END);

Это работает, потому что Oracle не будет помещать в индекс пустые значения, возвращаемые инструкцией CASE.

2 голосов
/ 08 октября 2011

Позвольте мне "переупаковать" мой оригинальный ответ .

Создайте таблицу следующим образом:

CREATE TABLE T ...;
CREATE INDEX T_PK_IDX ON T (C_I, CASE WHEN C_D IS NULL THEN 1 ELSE NULL END);
ALTER TABLE T ADD CONSTRAINT T_PK PRIMARY KEY (C_I) USING INDEX T_PK_IDX;

И запрос так:

SELECT * FROM T
WHERE
    C_I > 'some value'
    AND (CASE WHEN C_D IS NULL THEN 1 ELSE NULL END) = 1

План запроса:

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...