Удаление разделов в Greenplum

У меня такой сценарий:

SELECT * FROM PACKAGE WHERE PACKAGE_TYPE IN ('BOX','CARD')

Таблица разделена по полю PACKAGE_TYPE. Предположим, что существует двадцать возможных значений для поля PACKAGE_TYPE. Итак, имеется двадцать разделов, включая разделы BOX, CARD и DEFAULT. При выполнении приведенного выше запроса удаление разделов происходит правильно, и сканируются только разделы BOX и CARD. Результат быстрый.

Однако, когда тот же запрос написан так:

SELECT * FROM PACKAGE WHERE PACKAGE_TYPE IN (SELECT PACKAGE_TYPE FROM PACKAGE_LIST_TABLE), где столбец PACKAGE_TYPE в PACKAGE_LIST_TABLE содержит два значения BOX и CARD.

При выполнении вышеуказанного запроса сканируются все 20 разделов. Это ухудшает производительность.

Кажется, что компилятор не может правильно идентифицировать второй запрос, и в результате получают доступ ко всем разделам.

Любые обходные пути, чтобы преодолеть это?

Заранее спасибо.


person Deepak    schedule 22.04.2015    source источник
comment
Удаление разделов обычно происходит на этапе компиляции выполнения запроса. Список необходимых разделов пока неизвестен.   -  person Gordon Linoff    schedule 22.04.2015
comment
Спасибо. Любые обходные пути, чтобы получить эту работу? Невозможно жестко закодировать значения в моем запросе.   -  person Deepak    schedule 22.04.2015


Ответы (1)


Страница руководства Postgres по разделам содержит это предостережение.

Исключение ограничений работает только в том случае, если предложение WHERE запроса содержит константы (или параметры, предоставленные извне). Например, сравнение с неизменяемой функцией, такой как CURRENT_TIMESTAMP, не может быть оптимизировано, поскольку планировщик не может знать, в какой раздел может попасть значение функции во время выполнения.

Чтобы устранить поиск в разделе, Postgres должен знать, при создании плана запроса, что никакие строки из этого раздела не являются релевантными. В вашем запросе это происходит только после завершения подзапроса, поэтому запрос придется разделить на две части, при этом вторая часть будет запланирована только после завершения первой.

Если разделы включают индекс для разделенного столбца (PACKAGE_TYPE), а также ограничение, планировщик может выбрать сканирование индекса для каждого раздела, что приведет к достаточно эффективному устранению неправильных разделов во время выполнения. тем не мение. (То есть будет 20 сканирований индекса, но для каждого потребуется очень мало ресурсов.)

Альтернативой может быть самостоятельное разделение запроса и динамическое построение SQL. Поскольку SELECT PACKAGE_TYPE FROM PACKAGE_LIST_TABLE может возвращать только до 20 различных значений, вы можете выбрать их в массив/набор в своем приложении или пользовательскую функцию. Затем вы можете передать их как литералы в предложении IN ( ... ), как в вашем первом примере (или, что то же самое, = ANY(array_expression)), и добиться устранения раздела.

person IMSoP    schedule 22.04.2015
comment
Большое спасибо. Я получил это. У меня только один вопрос. Я попытался построить SQL динамически. Но похоже, что массив не распознается компилятором, и я получаю эту ошибку: ОШИБКА: оператор не уникален: неизвестно || переменный характер[] - person Deepak; 23.04.2015
comment
Мой оператор выполнения выглядит так: ARRVAR character Variing[]; ARRVAR: = МАССИВ (ВЫБЕРИТЕ PACKAGE_ID ИЗ PACKAGE_LIST_TABLE); выполнить 'UPDATE PACKAGE_TYPE SET PACKAGE_DT = CURRENT_DATE WHERE PACKAGE_ID = any('||ARRVAR||')'; Что мне не хватает? Как заставить массив работать в динамическом запросе? - person Deepak; 23.04.2015
comment
Эта ошибка связана не с динамическим запросом, а с тем, что вы пытаетесь объединить массив в строку, а Postgres не знает, что вы имеете в виду. У меня нет под рукой среды для проверки, но я думаю, что вы можете вообще обойтись без динамической строки SQL внутри функции, просто написав UPDATE PACKAGE_TYPE SET PACKAGE_DT = CURRENT_DATE WHERE PACKAGE_ID = any(ARRVAR); - person IMSoP; 23.04.2015
comment
Спасибо. Я попытался дать прямой оператор UPDATE внутри функции. Но запрос занимал время, аналогичное запросу, в котором нет предложения WHERE в столбце раздела. Поскольку запрос был внутри функции, я не смог проверить, затронул ли он все разделы или нет, поскольку postgres ничего не показал о сканировании разделов, когда я запускал объяснение анализа. Однако я понял, что удаления разделов не произошло, учитывая общее время работы. Таким образом, можно либо передать его как динамический запрос, либо добавить все идентификаторы пакетов, сохранить их в одной символьной переменной, а затем поместить в предложение WHERE. - person Deepak; 23.04.2015
comment
Неважно, я понял способ из вашей подсказки - попытаться объединить массив в строку. Я использовал это - CHARVAR := ''''||array_to_string(ARRAY(SELECT PACKAGE_ID FROM PACKAGE_LIST_TABLE), ''',''')||''''; . - person Deepak; 23.04.2015
comment
IMSoP, проблема удаления разделов снова всплыла на поверхность с оператором вставки даже после замены предложения where символьной переменной и запуска его как динамического запроса. Устранение раздела не произошло, когда была запущена вставка, и запрос, похоже, занимает много времени. UPDATE по-прежнему отлично работает с устранением разделов. Существуют ли какие-либо различия в том, как операторы INSERT и UPDATE выполняются в динамическом запросе? - person Deepak; 26.04.2015