Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pagination is extremely slow on larger datasets #563

Closed
Miguel-Serejo opened this issue Feb 12, 2020 · 1 comment · Fixed by #611
Closed

Pagination is extremely slow on larger datasets #563

Miguel-Serejo opened this issue Feb 12, 2020 · 1 comment · Fixed by #611

Comments

@Miguel-Serejo
Copy link

Miguel-Serejo commented Feb 12, 2020

Summary of problem or feature request

When paginating a query with a result set of nearly a million records, the query executes very slowly (>10 seconds).

Testing the generated query on Oracle SQL Developer, the query takes about 8 seconds.

A modification to the pagination query makes the query nearly instant, by using a combination of rownum >= $start and rownum <= $end instead of rownum between $start and end. This is the pagination method explained here: https://blogs.oracle.com/oraclemagazine/on-rownum-and-limiting-results which was tested to be the fastest pagination option by https://stackoverflow.com/a/6536249

I altered the generated query in OracleGrammar.php and got the query down from 5-12 seconds to 5-20 milliseconds:

/**
     * Compile a common table expression for a query.
     *
     * @param  string $sql
     * @param  string $constraint
     * @param Builder $query
     * @return string
     */
    protected function compileTableExpression($sql, $constraint, $query)
    {
        if ($query->limit == 1 && is_null($query->offset)) {
            return "select * from ({$sql}) where rownum {$constraint}";
        }

        if (!is_null($query->limit && !is_null($query->offset))) {
          $start  = $query->offset + 1;
          $finish = $query->offset + $query->limit;
          return "select t2.* from ( select rownum AS \"rn\", t1.* from ({$sql}) t1 where rownum <= {$finish}) t2 where t2.\"rn\" >= {$start}";
        }

        return "select t2.* from ( select rownum AS \"rn\", t1.* from ({$sql}) t1 ) t2 where t2.\"rn\" {$constraint}";
    }

Here's an image album containing screenshots from query execution both in SQL Developer and in laravel, as shown by debugbar. Please note I did not screencap "cold" queries, so the values here are somewhat faster than they normally would be for first requests:

https://imgur.com/a/c0vzsTE

Note how the between method does not make use of the STOPKEY operation, which makes it much slower.

I'm unsure if this behavior is the same on more recent versions of oracle. If anyone can test the changes on later versions I'd appreciate it.

System details

  • Operating System windows 10 / ubuntu 16.04 (same behavior)
  • PHP Version 7.2
  • Laravel Version 6.14.0
  • Laravel-OCI8 Version 6.1.0
  • Oracle Server Version 11g (11.2.0.2.0 - Production)
@yajra
Copy link
Owner

yajra commented Dec 6, 2020

Sorry for late reply. I'm definitely open to improving the pagination and will give your suggestions a try. Also, please do not hesitate to submit a PR for optimizations/suggestions. Thanks!

yajra added a commit that referenced this issue Dec 6, 2020
@yajra yajra closed this as completed in #611 Dec 6, 2020
yajra added a commit that referenced this issue Dec 6, 2020
* 8.x:
  Bump v8.2.1 🚀
  Add model insert tests.
  Add test for single insert.
  Fix binding values.
  Add failing tests for #558.
  Bump v8.2.0 🚀
  Fix cs.
  Fix pagination tests.
  Enhance pagination as suggested on #563.
  Fix docs.
  Bump v8.1.3 🚀
  Apply fixes from StyleCI
  Compare using actual db count.
  Use lower column name on column listing.
  Fix test suffix.
  Add failing tests for #596.
@github-actions github-actions bot locked and limited conversation to collaborators Oct 13, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants