Postgres LIMIT/OFFSET奇怪的行为

yer*_*syl 2 sql postgresql limit

我正在使用PostgreSQL 9.6.我有一个查询像这样:

SELECT anon_1.id AS anon_1_id, anon_1.is_valid AS anon_1_is_valid, anon_1.first_name AS anon_1_first_name, anon_1.last_name AS anon_1_last_name,
anon_1.patronymic_name AS anon_1_patronymic_name,
anon_1.experience AS anon_1_experience, anon_1.user_id AS anon_1_user_id, anon_1.rating_points as rating_points

FROM (SELECT DISTINCT ON (doctors.id) doctors.id AS id, doctors.created_at AS created_at, doctors.updated_at AS updated_at, doctors.is_valid AS is_valid, doctors.pretty_url AS pretty_url, doctors.first_name AS first_name, doctors.last_name AS last_name, doctors.patronymic_name AS patronymic_name, doctors.phone AS phone, doctors.birthday AS birthday, doctors.avatar AS avatar, doctors.experience AS experience, doctors.science_degree AS science_degree, doctors.sex_id AS sex_id, doctors.yclients_staff_id AS yclients_staff_id, doctors.user_id AS user_id, doctor_has_specialties.rating_points AS rating_points, clinic_branch_has_doctors.price AS price, clinic_branch_has_doctors.doctor_type AS doctor_type, clinic_branch_has_doctors.is_house_call AS is_house_call, clinic_branch_has_doctors.house_call_price AS house_call_price 
FROM doctors
      JOIN doctor_has_specialties ON doctors.id = doctor_has_specialties.doctor_id 
      JOIN clinic_branch_has_doctors ON doctor_has_specialties.id = clinic_branch_has_doctors.doctor_has_specialty_id 
      JOIN clinic_branches ON clinic_branches.id = clinic_branch_has_doctors.clinic_branch_id 
      JOIN city_areas ON city_areas.id = clinic_branches.city_area_id 
      JOIN cities ON cities.id = city_areas.city_id 
WHERE doctors.is_valid = true 
      AND clinic_branch_has_doctors.is_valid = true 
      AND clinic_branches.is_valid = true 
      AND doctor_has_specialties.specialty_id = 1
      AND cities.id = 1) AS anon_1 ORDER BY anon_1.rating_points DESC 
 LIMIT 100 OFFSET 0
Run Code Online (Sandbox Code Playgroud)

这里查询最重要的部分是最后一个,LIMIT和OFFSET.当我运行此查询时,我的所有数据最多可达100行.一切都很好.以下是pgAdmin的截图:

在此输入图像描述

这里注意到行为20的行.现在如果我尝试OFFSET 10,我从第11行得到我的数据,这是id为22的对象.一切都很好.但如果我尝试OFFSET 10 LIMIT 10,我会得到奇怪的结果.主要出现id为20的行,但不应该出现.这是截图: 在此输入图像描述

不知道那有什么问题.是Postgres的bug吗?或者我做错了什么.

Tim*_*sen 11

这里没有"bug".您指定了以下顺序,该顺序在应用时LIMIT和使用时OFFSET使用:

ORDER BY anon_1.rating_points DESC
Run Code Online (Sandbox Code Playgroud)

但是,如果两个或多个记录使用相同的rating_points值绑定,Postgres不保证订购的顺序.这就是为什么你看到一个用户anon_id_120明显走动.Postgres没有做错任何事; 它已经履行了你的订单要求rating_points,但你从来没有告诉它在领带的情况下该做什么.

要解决此问题,您可以向以下内容添加第二个条件ORDER BY:

ORDER BY
    anon_1.rating_points DESC,
    anon_id_1
Run Code Online (Sandbox Code Playgroud)

这将打破关于排序的关系,并且,假设anon_id_1是主键,结果在进行此更改后似乎是稳定的.