При написании операторов SQL для разделенных таблиц можно рассматривать разделы как единую виртуальную таблицу или же указывать в операторах названия конкретных разделов. Если оператор DML применяется к виртуальной таблице, оптимизатор Oracle определяет раздел или разделы, с которыми будет производиться работа. Для оператора INSERT при определении того, в какой раздел помещать какую строку, оптимизатор использует значения ключа разделения. В операторах UPDATE, DELETE и SELECT для определения разделов, которые будут просматриваться, оптимизатор использует условия инструкции WHERE, а также информацию локальных и глобальных индексов.
Если вы знаете, что оператор DML затрагивает только один раздел, и знаете название этого раздела, то можете использовать инструкцию PART ITION, чтобы сообщить оптимизатору, с каким разделом работать. Например, если вы хотите обобщить заказы за 2000 год и знаете, что для таблицы cust_order выполнено разделение по диапазону по годам, то можете написать такой запрос:
SELECT COUNT(*) tot_orders, SUM(sale_price) tot_sales FROM cust_order PARTITION (orders_2000) WHERE cancelled_dt IS NULL;
Обратите внимание, что в инструкции WHERE запроса не указан диапазон дат, хотя таблица и содержит данные за несколько лет. Так как указан раздел orders_2000, запрос будет обобщать только данные за 2000 год, и нет необходимости проверять дату каждого заказа.
Если для таблицы выполнено композитное разделение, можно использовать инструкцию SUBPARTITION для указания отдельного подраздела таблицы. Например, следующий оператор удаляет все строки подраздела orders_2000_s1 таблицы cust_crder, для которой было выполнено композитное разделение:
DELETE FROM cust_order SUBPARTITION (orders_2000_s1);
Можно также использовать инструкцию PARTITION для удаления всего набора подразделов, входящих в данный раздел:
DELETE FROM cust_order PARTITION (orders_2000);
Такой оператор удалит все строки подразделов orders_2000_s1, orders_2000_s2, orders_2000_s3 и orders_2000_s4 таблицы cust_order.
Приведем несколько фактов, о которых необходимо помнить при работе с разделенными таблицами:
- Если оптимизатор определяет, что для вычисления инструкции WHERE оператора UPDATE, DELETE или SELECT необходим просмотр двух или более разделов, разделы таблицы и/или индекса могут просматриваться параллельно. Поэтому в зависимости от доступных Oracle системных ресурсов просмотр разделенной таблицы может быть выполнен гораздо быстрее, чем просмотр неразделенной таблицы.
- Так как хеш-разделение распределяет данные по разделам случайным образом (в действительности данные распределяются не случайным образом, но вам будет казаться именно так, поскольку у пае нет доступа к хеш-функции), непонятно, как использовать инструкцию PARTITION для таблиц с хеш-разделением и инструкцию SUBPARTITION для таблиц с композитным разделением - ведь неизвестно, куда какие данные попали. Единственный разумный план действий, приходящий в голову, относится к случаю, когда необходимо изменить все строки таблицы, но размер сегмента отката недостаточен для изменения всех строк в одной транзакции. Тогда можно выполнить оператор UPDATE или DELETE для каждого раздела или подраздела, а после завершения работы каждого оператора выполнить инструкцию COMMIT.
- Администратор базы данных в любой момент может объединить несколько разделов, разбить раздел на подразделы или удалить раздел. Поэтому будьте внимательны при явном указании названий разделов в операторах DML. В противном случае оператор может не выполниться или, что еще хуже, выполниться не для того набора данных, из-за того что вы не знали об объединении или разбиении разделов. Стоит совместно с вашим администратором БД выработать правила по использованию названий разделов в операторах DML.
Если вы хотите обратиться к одному разделу или подразделу, но не хотите засорять код названиями разделов, подумайте о создании представлений, скрывающих названия разделов:
CREATE VIEW cust_order_2000 AS SELECT * FROM oust_order PARTITION (orders_2000);
Затем можно применять операторы SQL к представлению:
SELECT orders_nbr, cust_nbr, sale_price, order_dt FROM cust_order_2000 WHERE quantity > 100;