PLSQL: Using pipelined function to overcome config issue in Apache Solr

Recently I was facing an issue with an SQL coming from Apache Solr. The query was working on delta updates (since last check), and was fired from three different Solr instances keeping 3 cpus pretty busy . The query was one of the top SQLs regarding LIO, and was doing 9 FULL TABLE SCANs (where only two of the tables was relatively small with only 24 and 68 blocks). The query was written into the Solr configuration file, and looked something like this (when caught in v$sql) :

SELECT *
FROM a_big_view
WHERE TAB4_ROW_DELETED != :"SYS_B_01"
  AND ( :"SYS_B_02" = :"SYS_B_03"
      OR TAB1_UPDATED > to_date(:"SYS_B_04", :"SYS_B_05") 
      OR TAB2_UPDATED > to_date(:"SYS_B_06", :"SYS_B_07")  
      OR TAB3_UPDATED > to_date(:"SYS_B_08", :"SYS_B_09")
);


The “:SYS_B_02 = :SYS_B_03” filter really makes it impossible for the optimizer to use an appropriate index. As you might recognize the bind variables are set by sessions running with cursor_sharing=FORCE. The original query in the configuration file looked something like this:

SELECT *
FROM a_big_view
WHERE TAB4_ROW_DELETED != 1
  AND ( 1 = $search_date
      OR TAB1_UPDATED > to_date($a_datetime, 'DD.MM.YYYY HH24:MI:SS') 
      OR TAB2_UPDATED > to_date($a_datetime, 'DD.MM.YYYY HH24:MI:SS')  
      OR TAB3_UPDATED > to_date($a_datetime, 'DD.MM.YYYY HH24:MI:SS')
);

The trouble was that the Solr configuration needed one definition of a query, which would give totally different outcomes or number of rows. The solution we choose was a pipelined function, which would allow us to do something like this:

SELECT * FROM table(solr_util.getbigview($check_name,$search_date)

The pipelined function would look something like this:

CREATE OR REPLACE TYPE t_big_view_row AS OBJECT (
  col1 number, 
  col1 varchar2(100),
  ...
)
/

CREATE OR REPLACE TYPE t_big_vew_tab AS TABLE OF t_big_view_row
/

CREATE OR REPLACE PACKAGE solr_util AS 
  -------------------------------
  -- Functions and procedures
  -------------------------------
  FUNCTION getbigview(check_name_i IN number, 
                      gt_date_i IN date default sysdate-1) return t_big_vew_tab pipelined;
  
END solr_util;
/

CREATE OR REPLACE PACKAGE BODY solr_util AS
  FUNCTION getbigview(check_name_i IN number, 
                      gt_date_i IN date default sysdate-1) return t_big_vew_tab pipelined IS 
  BEGIN
    IF (check_name_i=1) THEN
      FOR rec in (
        SELECT t_big_view_row(
                col1, col2, ...
             ) row
        FROM (SELECT * 
              FROM a_big_view
              WHERE TAB1_UPDATED  > gt_date_i              
                AND TAB4_ROW_DELETED = 0
            UNION
            SELECT * 
              FROM a_big_view
              WHERE TAB2_UPDATED > gt_date_i
                AND TAB4_ROW_DELETED = 0
            UNION
            SELECT * 
              FROM a_big_view
              WHERE TAB3_UPDATED > gt_date_i
                AND TAB4_ROW_DELETED = 0)
        )
      LOOP
        PIPE ROW (rec.row);
      END LOOP;
    ELSE 
      FOR rec IN (
        SELECT t_big_view_row(
                col1, col2, ...
             ) row
        FROM a_big_view
        WHERE TAB4_ROW_DELETED = 0
        )
      LOOP
        PIPE ROW (rec.row);
      END LOOP;
    END IF;
    
  END getbigview;
END solr_util;
/

Post a Comment

Your email is never published nor shared. Required fields are marked *