2012-09-06 14 views
8

Tengo problemas para optimizar una consulta de Oracle después de una actualización a Oracle 11g y este problema me está empezando a poner un poco loco.¿La vinculación de enlace está deshabilitada en las consultas distribuidas?

Nota, esta pregunta se ha editado por completo ahora porque tengo más información después de crear un caso de prueba simple. La pregunta original está disponible aquí: https://stackoverflow.com/revisions/12304320/1.

Este problema es que al unir dos tablas, una de las cuales tiene una condición between en una columna de fecha, si la consulta se une a una tabla remota, no es posible vincularla.

Aquí hay un caso de prueba para ayudar a reproducir el problema. Primero configure dos tablas fuente. La primera es una lista de fechas, siendo el primer día del mes, que se remonta treinta años

create table mike_temp_etl_control 
as 
select 
    add_months(trunc(sysdate, 'MM'), 1-row_count) as reporting_date 
from (
    select level as row_count 
    from dual 
    connect by level < 360 
); 

A continuación, algunos datos procedentes de dba_objects:

create table mike_temp_dba_objects as 
select owner, object_name, subobject_name, object_id, created 
from dba_objects 
union all 
select owner, object_name, subobject_name, object_id, created 
from dba_objects; 

A continuación, crear una mesa vacía para ejecutar los datos de a:

create table mike_temp_1 
as 
select 
    a.OWNER, 
    a.OBJECT_NAME, 
    a.SUBOBJECT_NAME, 
    a.OBJECT_ID, 
    a.CREATED, 
    b.REPORTING_DATE 
from 
    mike_temp_dba_objects a 
    join mike_temp_etl_control b on (
     b.reporting_date between add_months(a.created, -24) and a.created) 
    where 1=2; 

A continuación, ejecute el código. Es posible que necesite crear una versión más grande mike_temp_dba_objects para ralentizar la consulta (o use algún otro método para obtener el plan de ejecución). Mientras se ejecuta la consulta, obtengo un plan de ejecución de la sesión ejecutando select * from table(dbms_xplan.display_cursor(sql_id => 'xxxxxxxxxxx')) desde una sesión diferente.

declare 
    pv_report_start_date date := date '2002-01-01'; 
    v_report_end_date date := date '2012-07-01'; 

begin 

    INSERT /*+ APPEND */ 
    INTO mike_temp_5 
    select 
    a.OWNER, 
    a.OBJECT_NAME, 
    a.SUBOBJECT_NAME, 
    a.OBJECT_ID, 
    a.CREATED, 
    b.REPORTING_DATE 
from 
    mike_temp_dba_objects a 
    join mike_temp_etl_control b on (
    b.reporting_date between add_months(a.created, -24) and a.created) 
    cross join [email protected] -- This line causes problems... 
where 
    b.reporting_date between add_months(pv_report_start_date, -12) and v_report_end_date; 

    rollback; 
end; 

Al tener una tabla remota en la consulta, la estimación de cardinalidad de la tabla mike_temp_etl_control es totalmente erróneo y no parece mirar a escondidas se unen a estar sucediendo.

El plan de ejecución de la consulta anterior se muestra a continuación:

--------------------------------------------------------------------------------------- 
| Id | Operation    | Name     | Rows | Bytes | Cost (%CPU)| 
--------------------------------------------------------------------------------------- 
| 0 | INSERT STATEMENT   |      |  |  | 373 (100)| 
| 1 | LOAD AS SELECT   |      |  |  |   | 
|* 2 | FILTER     |      |  |  |   | 
| 3 | MERGE JOIN   |      |  5 | 655 | 373 (21)| 
| 4 |  SORT JOIN   |      | 1096 | 130K| 370 (20)| 
| 5 |  MERGE JOIN CARTESIAN|      | 1096 | 130K| 369 (20)| 
| 6 |  REMOTE    | DUAL     |  1 |  |  2 (0)| 
| 7 |  BUFFER SORT  |      | 1096 | 130K| 367 (20)| 
|* 8 |  TABLE ACCESS FULL | MIKE_TEMP_DBA_OBJECTS | 1096 | 130K| 367 (20)| 
|* 9 |  FILTER    |      |  |  |   | 
|* 10 |  SORT JOIN   |      |  2 | 18 |  3 (34)| 
|* 11 |  TABLE ACCESS FULL | MIKE_TEMP_ETL_CONTROL |  2 | 18 |  2 (0)| 
--------------------------------------------------------------------------------------- 

Si luego vuelva a colocar el mando a distancia dual con la versión local tengo la cardinalidad correcto (139 en lugar de 2):

------------------------------------------------------------------------------------- 
| Id | Operation    | Name     | Rows | Bytes | Cost (%CPU)| 
------------------------------------------------------------------------------------- 
| 0 | INSERT STATEMENT  |      |  |  | 10682 (100)| 
| 1 | LOAD AS SELECT  |      |  |  |   | 
|* 2 | FILTER    |      |  |  |   | 
| 3 | MERGE JOIN   |      | 152K| 19M| 10682 (3)| 
| 4 |  SORT JOIN   |      | 438K| 51M| 10632 (2)| 
| 5 |  NESTED LOOPS  |      | 438K| 51M| 369 (20)| 
| 6 |  FAST DUAL  |      |  1 |  |  2 (0)| 
|* 7 |  TABLE ACCESS FULL| MIKE_TEMP_DBA_OBJECTS | 438K| 51M| 367 (20)| 
|* 8 |  FILTER    |      |  |  |   | 
|* 9 |  SORT JOIN   |      | 139 | 1251 |  3 (34)| 
|* 10 |  TABLE ACCESS FULL| MIKE_TEMP_ETL_CONTROL | 139 | 1251 |  2 (0)| 
------------------------------------------------------------------------------------- 

Entonces, supongo que la pregunta es ¿cómo puedo calcular la cardinalidad correcta? ¿Es esto un error de Oracle o es este el comportamiento esperado?

+0

Para deshacerse de las cosas fáciles, ¿ha vuelto a reunir [estadísticas] (http://docs.oracle.com/cd/E11882_01/server.112/e25494/general002.htm#ADMIN11525) sobre la mesa? – Ben

+0

Sí, todas las estadísticas deberían ser frescas. Sin embargo, lo comprobaré dos veces mañana. Es parte de una carga de ETL del almacén de datos, con estadísticas recopiladas en todo lo que ocurre –

+0

Sé que había un error en las versiones> 11.1 que tenía una ronda de trabajo que incluía establecer el parámetro "_optim_peek_user_binds" en falso. Esto puede afectar al optimizador pero no sé exactamente cómo. Puede verificar si este parámetro está configurado como verdadero o falso, debe ser cierto para un rendimiento máximo. El error provoca errores ORA-3137. – Gisli

Respuesta

1

Creo que debería meterse en el muestreo dinámico. Funciona en 11g de manera diferente, así que puede ser la razón de tus problemas.

Cuestiones relacionadas