Из-за уязвимости SQL-инъекции я бы предложил решение, подобное этому
V_sql VARCHAR2(10000):='SELECT
SV_ACC_REG.ACC_REG_ID AS ACC_REG_ID ,
SV_ACC_REG.PRODUCT_ID AS PRODUCT_ID ,
GEN_PRODUCT.FULL_NAME AS PRODUCT_NAME ,
...
SV_ACC_REG.IS_OLD AS IS_OLD ,
SV_ACC_REG.IS_NO_PROFIT_CALC AS IS_NO_PROFIT_CALC ,
SV_ACC_REG.IS_SIX_M_PROFIT_CALC AS IS_SIX_M_PROFIT_CALC ,
SV_ACC_REG.IS_SEND_DPMG ,
SV_CUSTOMER_INFO.CUSTOMER_NAME AS CUSTOMER_NAME
FROM SV_ACC_REG
LEFT JOIN GEN_PRODUCT ON SV_ACC_REG.PRODUCT_ID=GEN_PRODUCT.PRODUCT_NO
LEFT JOIN SV_CUSTOMER_INFO ON SV_ACC_REG.ACC_REG_ID = SV_CUSTOMER_INFO.ACC_REG_ID';
V_WHERE VARCHAR2(500);
cur INTEGER := DBMS_SQL.OPEN_CURSOR;
curRef SYS_REFCURSOR;
ret INTEGER;
BEGIN
IF p_ACC_REG_ID IS NOT NULL THEN
V_WHERE := V_WHERE || ' AND SV_ACC_REG.ACC_REG_ID = :p_ACC_REG_ID';
END IF;
IF p_PRODUCT_ID IS NOT NULL THEN
V_WHERE := V_WHERE || ' AND SV_ACC_REG.PRODUCT_ID = :p_PRODUCT_ID';
END IF;
IF p_STATUS IS NOT NULL THEN
V_WHERE := V_WHERE || ' AND SV_ACC_REG.STATUS = :p_STATUS';
END IF;
IF p_IS_TRANSFER IS NOT NULL THEN
V_WHERE := V_WHERE || ' AND SV_ACC_REG.IS_TRANSFER = :p_IS_TRANSFER';
END IF;
IF p_SO_NO IS NOT NULL THEN
V_WHERE := V_WHERE || ' AND SV_ACC_REG.SO_NO = :p_SO_NO';
END IF;
IF p_IS_OLD IS NOT NULL THEN
V_WHERE := V_WHERE || ' AND SV_ACC_REG.IS_OLD = :p_IS_OLD';
END IF;
IF p_IS_SEND_DPMG IS NOT NULL THEN
V_WHERE := V_WHERE || ' AND SV_ACC_REG.IS_SEND_DPMG = :p_IS_SEND_DPMG';
END IF;
IF p_IS_SIX_M_PROFIT_CALC IS NOT NULL THEN
V_WHERE := V_WHERE || ' AND IS_SIX_M_PROFIT_CALC= :p_IS_SIX_M_PROFIT_CALC';
END IF;
V_WHERE := REGEXP_REPLACE(V_WHERE, '^ AND', 'WHERE');
V_sql := V_sql || V_WHERE ||' ORDER BY SV_ACC_REG.ACC_REG_ID ASC';
DBMS_SQL.PARSE(cur, V_sql, DBMS_SQL.NATIVE);
IF p_ACC_REG_ID IS NOT NULL THEN
DBMS_SQL.BIND_VARIABLE(cur, ':p_ACC_REG_ID', p_ACC_REG_ID);
END IF;
IF p_PRODUCT_ID IS NOT NULL THEN
DBMS_SQL.BIND_VARIABLE(cur, ':p_PRODUCT_ID', p_PRODUCT_ID);
END IF;
IF p_STATUS IS NOT NULL THEN
DBMS_SQL.BIND_VARIABLE(cur, ':p_STATUS', p_STATUS);
END IF;
IF p_IS_TRANSFER IS NOT NULL THEN
DBMS_SQL.BIND_VARIABLE(cur, ':p_IS_TRANSFER', p_IS_TRANSFER);
END IF;
IF p_SO_NO IS NOT NULL THEN
DBMS_SQL.BIND_VARIABLE(cur, ':p_SO_NO', p_SO_NO);
END IF;
IF p_IS_OLD IS NOT NULL THEN
DBMS_SQL.BIND_VARIABLE(cur, ':p_IS_OLD', p_IS_OLD);
END IF;
IF p_IS_SEND_DPMG IS NOT NULL THEN
DBMS_SQL.BIND_VARIABLE(cur, ':IS_SEND_DPMG', IS_SEND_DPMG);
END IF;
IF p_IS_SIX_M_PROFIT_CALC IS NOT NULL THEN
DBMS_SQL.BIND_VARIABLE(cur, ':p_IS_SIX_M_PROFIT_CALC', p_IS_SIX_M_PROFIT_CALC );
END IF;
ret := DBMS_SQL.EXECUTE(cur);
curRef := DBMS_SQL.TO_REFCURSOR(cur);
END;
Что касается производительности, я бы рекомендовал создавать отдельные индексы для каждого столбца, который может иметься в условии WHERE, то есть один столбец на индекс. Oracle может комбинировать индексы (см. Примеры https://jonathanlewis.wordpress.com/2010/11/26/index-join-2/),, однако, если вы не форсируете его с помощью подсказки INDEX_JOIN
, это может быть очень редко. Обычно Oracle будет использовать только самый селективный индекс. Например, если результат SV_ACC_REG.PRODUCT_ID = 12345
возвращает только пару строк, тогда как другие условия / индексы больше не имеют значения с точки зрения производительности.
Для комбинаций, которые используются очень часто, вы можете рассмотреть выделенные составные индексы.
Столбцы SV_ACC_REG.STATUS
, SV_ACC_REG.IS_SEND_DPMG
, SV_ACC_REG.IS_TRANSFER
, SV_ACC_REG.IS_OLD
, IS_SIX_M_PROFIT_CALC
, кажется, имеют очень низкую мощность, я предполагаю, что они просто содержат значения Yes
и No
или аналогичные. Попробуйте использовать Bitmap-Indexes для этих столбцов. Битовые индексы на самом деле предназначены для объединения друг с другом, поэтому они работают наиболее эффективно.
Однако растровые индексы не подходят для приложений OLTP, т. Е. Их не следует использовать, когда часто изменяются данные таблицы (DELETE, INSERT, UPDATE). Становится еще хуже, если такие изменения выполняются несколькими сеансами одновременно.
Функция Контроль индекса должен помочь вам обнаружить бесполезные индексы.