Distinction on meta value on pre_get_posts

DISCLAIMER : Not a WordPress Expert, Just an old MySQL DBA

Here is your original generated SQL

SELECT SQL_CALC_FOUND_ROWS  wp_posts.ID
FROM wp_posts
    INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
WHERE 1=1  AND
    wp_posts.post_type="post" AND
    (wp_posts.post_status="publish" OR wp_posts.post_status="private") AND
    ( (
        wp_postmeta.meta_key = '_position' AND
        CAST(wp_postmeta.meta_value AS CHAR) > '0'
    ) )
GROUP BY wp_posts.ID, wp_postmeta.meta_value
ORDER BY wp_postmeta.meta_value+0 ASC, wp_posts.post_date DESC LIMIT 0, 31

What you are looking for is the minimum ID for any given position, perhaps something like:

SELECT SQL_CALC_FOUND_ROWS  MIN(wp_posts.ID)
FROM wp_posts
    INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
WHERE 1=1  AND
    wp_posts.post_type="post" AND
    (wp_posts.post_status="publish" OR wp_posts.post_status="private") AND
    ( (
        wp_postmeta.meta_key = '_position' AND
        CAST(wp_postmeta.meta_value AS CHAR) > '0'
    ) )
GROUP BY (wp_postmeta.meta_value+0);