Commit Graph

10 Commits

Author SHA1 Message Date
Yorick Peterse e1c3077e4b Added benchmark for ReferenceFilter 2015-10-20 15:53:22 +02:00
Yorick Peterse 4ff75e3179 Improve performance of sorting milestone issues
This cuts down the time it takes to sort issues of a milestone by about
10x. In the previous setup the code would run a SQL query for every
issue that had to be sorted. The new setup instead runs a single SQL
query to update all the given issues at once.

The attached benchmark used to run at around 60 iterations per second,
using the new setup this hovers around 600 iterations per second. Timing
wise a request to update a milestone with 40-something issues would take
about 760 ms, in the new setup this only takes about 130 ms.

Fixes #3066
2015-10-19 11:37:14 +02:00
Yorick Peterse 5ce933599c Merge branch 'user-by-login-performance' into 'master'
Improve User.by_login performance

This greatly speeds up the performance of `User.by_login`. I adopted some changes from @haynes in this patch, the credits go to him for coming up with those originally.

Fixes #2341

See merge request !1545
2015-10-15 13:41:17 +00:00
Yorick Peterse 3025b71141 Improve ProjectTeam#max_member_access performance
By comparing objects in Ruby we can greatly improve the performance of
this method. In the worst case (should no data be eager loaded) this
will run the same amount of queries as before, in the best case (when
data _is_ eager loadeD) it requires no queries at all.

The added benchmark used to produce around 273 iterations per second.
With this commit this has been increased to almost 40 000 iterations per
second: a speedup of roughly 145 times.

Combined with eager loading Note associations this results in about 30
queries less when viewing a single issue, this in turn cuts down the
loading time by 30-40%.
2015-10-15 12:05:01 +02:00
Yorick Peterse 72f428c7d2 Improve performance of User.by_login
Performance is improved in two steps:

1. On PostgreSQL an expression index is used for checking lower(email)
   and lower(username).
2. The check to determine if we're searching for a username or Email is
   moved to Ruby. Thanks to @haynes for suggesting and writing the
   initial implementation of this.

Moving the check to Ruby makes this method an additional 1.5 times
faster compared to doing the check in the SQL query.

With performance being improved I've now also tweaked the amount of
iterations required by the User.by_login benchmark. This method now runs
between 900 and 1000 iterations per second.
2015-10-15 11:58:25 +02:00
Dmitriy Zaporozhets 0a8f90a040
Merge remote-tracking branch 'public/project-find-with-namespace-performance'
Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
2015-10-08 17:42:14 +02:00
Yorick Peterse 03417456f0 Revamp finding projects by namespaces
By using a JOIN we can remove the need for using 2 separate queries to
find a project by its namespace. Combined with an index (only needed for
PostgreSQL) this reduces the query time from ~245 ms (~520 ms for the
first call) down to roughly 10 ms (~15 ms for the first call).
2015-10-08 14:35:32 +02:00
Yorick Peterse 7adf9a52ba Added benchmarks for finding trending projects 2015-10-06 17:26:32 +02:00
Yorick Peterse 22506ddc50 Added benchmark_subject method for benchmarks
This class method can be used in "describe" blocks to specify the
subject of a benchmark. This lets you write:

    benchmark_subject { Foo }

instead of:

    benchmark_subject { -> { Foo } }
2015-10-05 10:51:24 +02:00
Yorick Peterse 19893a1c10 Basic setup for an RSpec based benchmark suite
This benchmark suite uses benchmark-ips
(https://github.com/evanphx/benchmark-ips) behind the scenes. Specs can
be turned into benchmark specs by setting "benchmark" to "true" in the
top-level describe block like so:

    describe SomeClass, benchmark: true do

    end

Writing benchmarks can be done using custom RSpec matchers, for example:

    describe MaruTheCat, benchmark: true do
      describe '#jump_in_box' do
        it 'should run 1000 iterations per second' do
          maru = described_class.new

          expect { maru.jump_in_box }.to iterate_per_second(1000)
        end
      end
    end

By default the "iterate_per_second" expectation requires a standard
deviation under 30% (this is just an arbitrary default for now). You can
change this by chaining "with_maximum_stddev" on the expectation:

    expect { maru.jump_in_box }.to iterate_per_second(1000)
      .with_maximum_stddev(10)

This will change the expectation to require a maximum deviation of 10%.

Alternatively you can use the it block style to write specs:

    describe MaruTheCat, benchmark: true do
      describe '#jump_in_box' do
        subject { -> { described_class.new } }

        it { is_expected.to iterate_per_second(1000) }
      end
    end

Because "iterate_per_second" operates on a block, opposed to a static
value, the "subject" method must return a Proc. This looks a bit goofy
but I have been unable to find a nice way around this.
2015-10-02 17:00:23 +02:00