The MySQL query being executed doesn't specify any "order" to the rows; MySQL is free to return the rows in any order it chooses, so it's possible that the "last 20" rows on one run of the query might differ from the "last 20" rows on a second run.
(We do observe repeated behavior when the statement is re-executed; it usually takes some DML operations, the addition of an index, or an OPTIMIZE table statement, to actually get a change in the results returned... but the point is, there is no "last 20" rows in the table. In MySQL, it's just a set of rows.)
To specify a specific sequence of the rows, add an ORDER BY
clause to the query. Assuming that you want to use the unique id
column to order the rows, and you want the last 20 rows, and you want them returned in ascending id sequence:
SELECT t.*
FROM ( SELECT u.*
FROM `$usern` u
ORDER BY u.id DESC
LIMIT 20
) t
ORDER BY t.id
And, yes, processing rows "in a loop" in PHP, just like you demonstrate, is a normative pattern.