Printing very slowly to template

phoenix
troubleshooting
#1

I am trying to transition my website from PHP to Elixir.

I am printing several records from my database (~8k) onto the page (in a table). In PHP, I used to echo each table row (

) and table data with the data inside (…)

With Elixir, I’m doing the same thing. I passed my proxy list that I retrieved via the DB to the .html.eex file. Then I have something like

<%= for {ip, port, country, last_checked} <- @proxies do %>
   a bunch of tr/tds here
<% end %>

The difference? On the same webserver (although running the phx.server in debug mode) it takes 6.97s for Phoenix, and 1.51s for PHP. The page appears in phoenix, but the content continues to get appended for a while after (I know because the scroll bar keeps moving higher)

What am I doing wrong here? Is this correct behavior (and its just that much slower?)?

#2

I’d guess the difference rather comes from the db selection part rather than from the rendering, so how exactly do you load the proxies from the db in php and elixir?

#3

How are you serving php and how are you serving phoenix requests? Maybe you’re doing something weird with template rendering (like outputing it as a stream)?
This looks like some kind of output buffering/html redraw issue (since each row is appended by the browser on the fly.

#4

With PHP, I am echo-ing each record in a for loop. With Elixir, I’m doing the same.

PHP:

                    foreach($rows as &$row) {
                        echo "<tr>";
                        echo "<td name=\"proxy\">".$row['ip'].":".$row['port']."</td>";
                        if(strcmp($row['country'], '--') != 0){
                            echo "<td class=\"unselectable\" name=\"country\">".Locale::getDisplayRegion('-'.$row['country'], 'en')."</td>";
                        } else{
                            echo "<td class=\"unselectable\" name=\"country\">N/A</td>";
                        }
                        if($row['last_checked'] != 0) {
                            //G:i:s
                            echo "<td class=\"unselectable\">".$row['last_checked']."</td>";
                        } else {
                            echo "<td class=\"unselectable\">N/A</td>";
                        }
                        echo "</tr>";
                    }

Elixir:

    <%= for {ip, port, country, last_checked} <- @proxies do %>
      <tr>
      <%# Proxy row %>
      <td name="proxy"><%= ip %>:<%= port %></td>
      <%# Country row %>
      <td class="unselectable" name="country">
      <%= country %>
      </td>
      <%# Last checked row %>
      <td class="unselectable">
      <%=
        cond do
          last_checked == 0 -> "N/A"
          true -> last_checked
        end
      %>
      </td>
    <% end %>
#5

The queries seem to be fine. Copy pasting the query from the debug and running it in MySQL shows it in fact takes lesser time (with the Elixir generated query). Here they are:

Elixir
SELECT p0.`ip`, p0.`port`, c1.`full_country`, p0.`last_checked` FROM `proxies` AS p0 INNER JOIN `country` AS c1 ON c1.`id` = p0.`country_id` WHERE (p0.`http` = 1) ORDER BY p0.`last_checked` DESC - 0.0267s

PHP
SELECT * FROM `proxies` WHERE `http` = 1 ORDER BY `last_checked` DESC - 0.036s

(yes, I changed the structure of the DB a little, hence the difference in queries)

#6

First, to make sure we’re doing apples to apples. Are you running in dev mode? Make sure to measure everything in MIX_ENV=prod. If using mix, make sure to load the page several times before counting the times, since mix lazy loads code and this can cause slow runtimes the first few times you run something.

#7

There is no INNER JOIN in the PHP query. Is this intentional?

#8

:wave:

I wonder if the issue could be with the web server, maybe cowboy chunks big responses somehow, that would explain the scroll bar behaviour. Can you try curling the page, and seeing if all of it is received at once? If so, then the browser might be at fault (slow rendering or something).