Perform calculations in SQL instead of app when creating sites (#2156)

This commit removes some Enum calls to rely on the database for
aggregating data. This improves performance when creating new sites,
especially if the user has multiple sites.
This commit is contained in:
Vinicius Brasil 2022-09-01 07:09:28 -07:00 committed by GitHub
parent 7683638b84
commit e417c82a26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 29 additions and 31 deletions

View File

@ -159,17 +159,16 @@ defmodule Plausible.Billing do
def last_two_billing_months_usage(user, today \\ Timex.today()) do
{first, second} = last_two_billing_cycles(user, today)
sites = Plausible.Sites.owned_by(user)
domains = Plausible.Sites.owned_sites_domains(user)
usage_for_sites = fn sites, date_range ->
domains = Enum.map(sites, & &1.domain)
usage_for_sites = fn domains, date_range ->
{pageviews, custom_events} = Plausible.Stats.Clickhouse.usage_breakdown(domains, date_range)
pageviews + custom_events
end
{
usage_for_sites.(sites, first),
usage_for_sites.(sites, second)
usage_for_sites.(domains, first),
usage_for_sites.(domains, second)
}
end
@ -194,7 +193,7 @@ defmodule Plausible.Billing do
end
def usage_breakdown(user) do
domains = Plausible.Sites.owned_by(user) |> Enum.map(& &1.domain)
domains = Plausible.Sites.owned_sites_domains(user)
Plausible.Stats.Clickhouse.usage_breakdown(domains)
end

View File

@ -1,12 +1,12 @@
defmodule Plausible.Sites do
use Plausible.Repo
alias Plausible.Site.SharedLink
import Ecto.Query
def create(user, params) do
count = Enum.count(owned_by(user))
limit = Plausible.Billing.sites_limit(user)
if count >= limit do
if owned_sites_count(user) >= limit do
{:error, :limit, limit}
else
site_changeset = Plausible.Site.changeset(%Plausible.Site{}, params)
@ -116,24 +116,25 @@ defmodule Plausible.Sites do
)
end
def owned_by(user) do
Repo.all(
from s in Plausible.Site,
join: sm in Plausible.Site.Membership,
on: sm.site_id == s.id,
where: sm.role == :owner,
where: sm.user_id == ^user.id
)
def owned_sites_count(user) do
user
|> owned_sites_query()
|> Repo.aggregate(:count)
end
def count_owned_by(user) do
Repo.one(
from s in Plausible.Site,
join: sm in Plausible.Site.Membership,
on: sm.site_id == s.id,
where: sm.role == :owner,
where: sm.user_id == ^user.id,
select: count(sm)
def owned_sites_domains(user) do
user
|> owned_sites_query()
|> select([site], site.domain)
|> Repo.all()
end
defp owned_sites_query(user) do
from(s in Plausible.Site,
join: sm in Plausible.Site.Membership,
on: sm.site_id == s.id,
where: sm.role == :owner,
where: sm.user_id == ^user.id
)
end

View File

@ -50,14 +50,12 @@ defmodule PlausibleWeb.SiteController do
end
def new(conn, _params) do
current_user = conn.assigns[:current_user] |> Repo.preload(site_memberships: :site)
owned_site_count =
current_user.site_memberships |> Enum.filter(fn m -> m.role == :owner end) |> Enum.count()
current_user = conn.assigns[:current_user]
owned_site_count = Plausible.Sites.owned_sites_count(current_user)
site_limit = Plausible.Billing.sites_limit(current_user)
is_at_limit = site_limit && owned_site_count >= site_limit
is_first_site = Enum.empty?(current_user.site_memberships)
is_first_site = owned_site_count == 0
changeset = Plausible.Site.changeset(%Plausible.Site{})
@ -72,7 +70,7 @@ defmodule PlausibleWeb.SiteController do
def create_site(conn, %{"site" => site_params}) do
user = conn.assigns[:current_user]
site_count = Enum.count(Plausible.Sites.owned_by(user))
site_count = Plausible.Sites.owned_sites_count(user)
is_first_site = site_count == 0
case Sites.create(user, site_params) do

View File

@ -131,7 +131,7 @@ defmodule Plausible.Workers.CheckUsage do
defp check_site_limit(subscriber) do
allowance = subscriber.enterprise_plan.site_limit
total_sites = Plausible.Sites.count_owned_by(subscriber)
total_sites = Plausible.Sites.owned_sites_count(subscriber)
if total_sites >= allowance do
{:over_limit, {total_sites, allowance}}