Search code examples
sqloracle-databasejoinquery-performance

Performance for multiple partitioned subqueries


I have a database with one main table and multiple history/log tables that stores the evolution over time of properties of some rows of main table. These properties are not stored on the main table itself, but must be queried from the relevant history/log table. All these tables are big (on the order of gigabytes).

I want to dump the whole main table and join the last entry of all the history/log tables.

Currently I do it via subqueries as follows:

WITH
  foo AS (
    SELECT
      ROW_NUMBER() OVER (PARTITION BY itemid ORDER BY date DESC) AS rownumber,
      ...
    FROM table1),
  bar AS (
    SELECT
      ROW_NUMBER() OVER (PARTITION BY itemid ORDER BY date DESC) AS rownumber,
      ...
    FROM table2)
SELECT
  ...
FROM maintable mt
JOIN foo foo ON foo.itemid = mt.itemid AND foo.rownumber = 1
JOIN bar bar ON foo.itemid = mt.itemid AND bar.rownumber = 1
WHERE ...

The problem is that this is very slow. Is there a faster solution to this problem?

I am only allowed to perform read-only queries on this database: I can not make any changes to it.


Solution

  • In actual Oracle versions it's usually better to use laterals/CROSS APPLY, because CBO (oracle cost-based optimizer) can transform them (DCL - lateral view decorrelation transformation) and use optimal join method depending on your circumstances/conditions (table statistics, cardinality, etc).

    So it would be something like this:

    SELECT
      ...
    FROM maintable mt
    CROSS APPLY (
          SELECT *
          FROM table1
          WHERE table1.itemid = mt.itemid
          ORDER BY date DESC
          fetch first 1 row only
          )
    CROSS APPLY (
          SELECT *
          FROM table2
          WHERE table2.itemid = mt.itemid
          ORDER BY date DESC
          fetch first 1 row only
          )
    WHERE ...
    

    PS. You haven't specified your oracle version, so my answer is for Oracle 12+