Skip to content

Commit 393b87f

Browse files
committed
Optimize SQL generation
1 parent b0ccc5f commit 393b87f

File tree

7 files changed

+857
-717
lines changed

7 files changed

+857
-717
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- MySQL adapter [#5](https://github.com/elixir-dbvisor/sql/pull/5).
1616
- PostgreSQL adapter [#5](https://github.com/elixir-dbvisor/sql/pull/5).
1717
- TDS adapter [#5](https://github.com/elixir-dbvisor/sql/pull/5).
18+
- Improve SQL generation with 4-600x compared to Ecto [#7](https://github.com/elixir-dbvisor/sql/pull/7).
1819

1920
### Deprecation
2021
- token_to_sql/2 is deprecated in favor of SQL.Token behaviour token_to_string/2 [#5](https://github.com/elixir-dbvisor/sql/pull/5).

bench.exs

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
import SQL
2+
import Ecto.Query
3+
defmodule SQL.Repo do
4+
use Ecto.Repo, otp_app: :sql, adapter: Ecto.Adapters.Postgres
5+
end
6+
Application.put_env(:sql, :ecto_repos, [SQL.Repo])
7+
Application.put_env(:sql, SQL.Repo, username: "postgres", password: "postgres", hostname: "localhost", database: "sql_test#{System.get_env("MIX_TEST_PARTITION")}", pool: Ecto.Adapters.SQL.Sandbox, pool_size: 10)
8+
SQL.Repo.start_link()
29
range = 1..10_000
310
Benchee.run(
411
%{
512
"to_stirng" => fn -> for _ <- range, do: to_string(~SQL[with recursive temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)]) end,
613
"to_sql" => fn -> for _ <- range, do: SQL.to_sql(~SQL[with recursive temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)]) end,
7-
"inspect" => fn -> for _ <- range, do: inspect(~SQL[with recursive temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)]) end
14+
"inspect" => fn -> for _ <- range, do: inspect(~SQL[with recursive temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)]) end,
15+
"ecto" => fn -> for _ <- range, do: SQL.Repo.to_sql(:all, "temp" |> recursive_ctes(true) |> with_cte("temp", as: ^union_all(select("temp", [t], %{n: 0, fact: 1}), ^where(select("temp", [t], [t.n+1, t.n+1*t.fact]), [t], t.n < 9))) |> select([t], [t.n])) end
816
},
917
time: 10,
1018
memory_time: 2

benchmarks/v0.2.0.md

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
➜ sql git:(optimize-sql-generation) ✗ mix sql.bench
2+
Compiling 1 file (.ex)
3+
Generated sql app
4+
Operating System: macOS
5+
CPU Information: Apple M1 Max
6+
Number of Available Cores: 10
7+
Available memory: 64 GB
8+
Elixir 1.18.0
9+
Erlang 27.2
10+
JIT enabled: true
11+
12+
Benchmark suite executing with the following configuration:
13+
warmup: 2 s
14+
time: 10 s
15+
memory time: 2 s
16+
reduction time: 0 ns
17+
parallel: 1
18+
inputs: none specified
19+
Estimated total run time: 56 s
20+
21+
Benchmarking Ecto.Repo.to_sql ...
22+
Benchmarking inspect ...
23+
Benchmarking to_sql ...
24+
Benchmarking to_stirng ...
25+
Calculating statistics...
26+
Formatting results...
27+
28+
Name ips average deviation median 99th %
29+
to_sql 4.74 K 0.21 ms ±20.20% 0.20 ms 0.32 ms
30+
to_stirng 4.51 K 0.22 ms ±3.60% 0.22 ms 0.26 ms
31+
inspect 0.24 K 4.09 ms ±2.96% 4.09 ms 4.36 ms
32+
Ecto.Repo.to_sql 0.00757 K 132.03 ms ±1.45% 131.80 ms 139.43 ms
33+
34+
Comparison:
35+
to_sql 4.74 K
36+
to_stirng 4.51 K - 1.05x slower +0.0108 ms
37+
inspect 0.24 K - 19.39x slower +3.88 ms
38+
Ecto.Repo.to_sql 0.00757 K - 626.20x slower +131.82 ms
39+
40+
Memory usage statistics:
41+
42+
Name Memory usage
43+
to_sql 0.38 MB
44+
to_stirng 0.153 MB - 0.40x memory usage -0.22888 MB
45+
inspect 4.88 MB - 12.80x memory usage +4.50 MB
46+
Ecto.Repo.to_sql 179.35 MB - 470.13x memory usage +178.97 MB
47+
48+
**All measurements for memory usage were the same**
49+
50+
➜ sql git:(optimize-sql-generation) ✗ mix sql.bench
51+
Compiling 1 file (.ex)
52+
Generated sql app
53+
Operating System: macOS
54+
CPU Information: Apple M1 Max
55+
Number of Available Cores: 10
56+
Available memory: 64 GB
57+
Elixir 1.18.0
58+
Erlang 27.2
59+
JIT enabled: true
60+
61+
Benchmark suite executing with the following configuration:
62+
warmup: 2 s
63+
time: 10 s
64+
memory time: 2 s
65+
reduction time: 0 ns
66+
parallel: 1
67+
inputs: none specified
68+
Estimated total run time: 56 s
69+
70+
Benchmarking ecto ...
71+
Benchmarking inspect ...
72+
Benchmarking to_sql ...
73+
Benchmarking to_stirng ...
74+
Calculating statistics...
75+
Formatting results...
76+
77+
Name ips average deviation median 99th %
78+
to_stirng 27.59 36.24 ms ±0.75% 36.22 ms 37.21 ms
79+
to_sql 27.45 36.42 ms ±0.47% 36.39 ms 36.93 ms
80+
inspect 24.53 40.76 ms ±1.07% 40.75 ms 41.60 ms
81+
ecto 6.96 143.65 ms ±1.37% 143.36 ms 148.62 ms
82+
83+
Comparison:
84+
to_stirng 27.59
85+
to_sql 27.45 - 1.00x slower +0.181 ms
86+
inspect 24.53 - 1.12x slower +4.52 ms
87+
ecto 6.96 - 3.96x slower +107.41 ms
88+
89+
Memory usage statistics:
90+
91+
Name Memory usage
92+
to_stirng 4.50 MB
93+
to_sql 4.73 MB - 1.05x memory usage +0.23 MB
94+
inspect 9.23 MB - 2.05x memory usage +4.73 MB
95+
ecto 202.87 MB - 45.11x memory usage +198.37 MB
96+
97+
**All measurements for memory usage were the same**

0 commit comments

Comments
 (0)