Skip to content

Instantly share code, notes, and snippets.

@bglusman
Created February 12, 2019 02:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bglusman/09f4fe3b6b0fbba3232544e3c16bdb6f to your computer and use it in GitHub Desktop.
Save bglusman/09f4fe3b6b0fbba3232544e3c16bdb6f to your computer and use it in GitHub Desktop.
defmodule Repo.Migrations.AddCountEstimateFunction do
use Ecto.Migration
def up do
create_function()
end
def down do
drop_function()
end
defp create_function() do
execute """
CREATE FUNCTION count_estimate(query text) RETURNS INTEGER AS
$$
DECLARE
rec record;
ROWS INTEGER;
BEGIN
FOR rec IN EXECUTE 'EXPLAIN ' || query LOOP
ROWS := SUBSTRING(rec."QUERY PLAN" FROM ' rows=([[:digit:]]+)');
EXIT WHEN ROWS IS NOT NULL;
END LOOP;
RETURN ROWS;
END
$$
LANGUAGE plpgsql;
"""
end
defp drop_function() do
execute "DROP FUNCTION count_estimate(query text);"
end
end
defmodule Repo do
...
def count_estimate(query) do
{iodata, params} = to_sql(:all, query)
%{rows: [[estimate]]} =
query!(IO.iodata_to_binary(["select count_estimate('#{iodata}')"]), params)
# I think maybe better UX since should only be used for "large numbers"
# and many ridiculous queries with 0 present return estimte of 1
if estimate == 1, do: 0, else: estimate
end
...
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment