Skip to content

Concatenate query list field once - #1325

Merged
josevalim merged 1 commit into
elixir-plug:mainfrom
preciz:concat-query-list-field-once
Aug 26, 2026
Merged

Concatenate query list field once#1325
josevalim merged 1 commit into
elixir-plug:mainfrom
preciz:concat-query-list-field-once

Conversation

@preciz

@preciz preciz commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Assited-by: Codex CLI:GPT 5.6 Sol

Concats field string once.
It's faster and uses less memory.

Bench:

Mix.install([:benchee])

defmodule Before do
  def encode({field, list}) do
    field
    |> encode_pair(list)
    |> IO.iodata_to_binary()
  end

  defp encode_pair(parent_field, list) when is_list(list) do
    mapper = fn value ->
      [?&, encode_pair(parent_field <> "[]", value)]
    end

    list
    |> Enum.flat_map(mapper)
    |> prune()
  end

  defp encode_pair(field, value), do: [field, ?= | to_string(value)]

  defp prune([?& | rest]), do: rest
  defp prune([]), do: []
end

defmodule After do
  def encode({parent_field, list}) do
    parent_field
    |> encode_pair(list)
    |> IO.iodata_to_binary()
  end

  defp encode_pair(parent_field, list) when is_list(list) do
    field = parent_field <> "[]"
    Enum.map_intersperse(list, ?&, fn value -> encode_pair(field, value) end)
  end

  defp encode_pair(field, value), do: [field, ?= | to_string(value)]
end

Benchee.run(
  %{
    "before" => &Before.encode/1,
    "after" => &After.encode/1
  },
  inputs: %{
    "5 tags" => {"tags", ~w(elixir phoenix plug http web)},
    "20 category IDs" => {"category_ids", Enum.to_list(1..20)},
    "100 record IDs" => {"record_ids", Enum.to_list(1..100)}
  },
  pre_check: :all_same,
  warmup: 1,
  time: 2,
  memory_time: 1
)

Results:

Operating System: Linux
CPU Information: AMD Ryzen 7 8845HS w
Number of Available Cores: 16
Available memory: 54.72 GB
Elixir 1.20.3
Erlang 29.0.5
JIT enabled: true

Benchmark suite executing with the following configuration:
warmup: 1 s
time: 2 s
memory time: 1 s
reduction time: 0 ns
parallel: 1
inputs: 100 record IDs, 20 category IDs, 5 tags
Estimated total run time: 24 s
Excluding outliers: false

Benchmarking after with input 100 record IDs ...
Benchmarking after with input 20 category IDs ...
Benchmarking after with input 5 tags ...
Benchmarking before with input 100 record IDs ...
Benchmarking before with input 20 category IDs ...
Benchmarking before with input 5 tags ...
Calculating statistics...
Formatting results...

##### With input 100 record IDs #####
Name             ips        average  deviation         median         99th %
after       149.27 K        6.70 μs    ±86.56%        6.40 μs       11.46 μs
before       75.19 K       13.30 μs    ±90.31%       10.03 μs       92.55 μs

Comparison: 
after       149.27 K
before       75.19 K - 1.99x slower +6.60 μs

Memory usage statistics:

Name      Memory usage
after          8.73 KB
before        18.02 KB - 2.07x memory usage +9.30 KB

**All measurements for memory usage were the same**

##### With input 20 category IDs #####
Name             ips        average  deviation         median         99th %
after       664.63 K        1.50 μs   ±597.09%        1.33 μs        2.60 μs
before      323.32 K        3.09 μs   ±482.35%        2.13 μs        7.21 μs

Comparison: 
after       664.63 K
before      323.32 K - 2.06x slower +1.59 μs

Memory usage statistics:

Name      Memory usage
after          1.85 KB
before         3.65 KB - 1.97x memory usage +1.80 KB

**All measurements for memory usage were the same**

##### With input 5 tags #####
Name             ips        average  deviation         median         99th %
after         3.39 M      295.24 ns   ±830.22%         251 ns         621 ns
before        1.43 M      700.15 ns  ±1525.31%         461 ns        1342 ns

Comparison: 
after         3.39 M
before        1.43 M - 2.37x slower +404.92 ns

Memory usage statistics:

Name      Memory usage
after            472 B
before           872 B - 1.85x memory usage +400 B

**All measurements for memory usage were the same**

@josevalim
josevalim merged commit 864c307 into elixir-plug:main Aug 26, 2026
2 checks passed
@josevalim

Copy link
Copy Markdown
Member

💚 💙 💜 💛 ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants