Postgres выбрать различный с другим порядком без использования подзапроса? - PullRequest
0 голосов
/ 15 января 2020

Есть много ответов о том, как сделать это, включая подзапрос, но подзапрос для нас оставляет производительность недостаточной. Похоже, что все результаты подзапроса определяются до выполнения внешнего запроса.

У нас есть структура базы данных, в которой Product содержит Variant , который содержит * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 10 * * * * * * * * * * * * * * * * * * * * * * * * '* * * * * * * * * * postgres, особенно когда необходимо соответствовать заказу, который не тот, который мы (или любой покупатель онлайн) хотел бы. База данных даже не такая большая: 28 миллионов строк Access 'и 15 000 продуктов. Без подзапроса и правильных индексов производительность очень хорошая, за 10 миллисекунд. С подзапросом это заканчивается в тысячах миллисекунд (это на M.2 P CIe SSD).

В этом примере я пытаюсь:

  1. Возвращать только 1 строку для каждого продукта
  2. Удовлетворять условию "где" (местоположение, могут быть другие вещи)
  3. Убедитесь, что мы сначала показываем на складе продукты
  4. Убедитесь, что мы сначала покажите самые дорогие продукты

Индекс точно соответствует этому. Любая помощь с благодарностью.

SELECT 
  * 
FROM 
  (
    SELECT 
      DISTINCT ON ("products_displayproduct"."id") "products_displayproduct"."id", 
      "products_displayproduct"."date_created", 
      "products_displayproduct"."date_updated", 
      "products_displayproduct"."name", 
      "products_displayproduct"."sub_title", 
      "products_displayproduct"."tags", 
      "products_displayproduct"."has_multiple_variants", 
      "products_displayproduct"."placement_id", 
      "products_displayproduct"."hidden_placement_category_id", 
      "products_displayproduct"."hidden_placement_super_category_id", 
      "products_displayproduct"."brand_id", 
      "products_displayproduct"."poster_image_id", 
      "products_displayproduct"."rating", 
      "products_displayproduct"."reviews", 
      "products_displayproduct"."is_toppick", 
      "products_displayproduct"."last_amalgamation", 
      "products_displayproduct"."search_index", 
      "products_displayproductaccess"."is_instock" as "subquery_instock", 
      "products_displayproductaccess"."price" as "subquery_price" 
    FROM 
      "products_displayproduct" 
      INNER JOIN "products_displayproductvariant" ON (
        "products_displayproduct"."id" = "products_displayproductvariant"."product_id"
      ) 
      INNER JOIN "products_displayproductaccess" ON (
        "products_displayproductvariant"."id" = "products_displayproductaccess"."product_variant_id"
      ) 
    WHERE 
      (
        "products_displayproductaccess"."location_id" IN (
          608, 65, 610, 69, 999, 72, 92, 79, 81, 84, 
          1045, 89, 601, 954, 603, 1276, 605, 607
        )
      ) 
    ORDER BY 
      "products_displayproduct"."id" ASC NULLS LAST, 
      "products_displayproductaccess"."is_instock" DESC NULLS LAST, 
      "products_displayproductaccess"."price" DESC NULLS LAST
  ) as subquery 
ORDER BY 
  "subquery"."subquery_instock" DESC, 
  "subquery"."subquery_price" DESC
LIMIT 10

1 Ответ

0 голосов
/ 15 января 2020

Я всегда обнаруживал, что при использовании DISTINCT мои запросы очень сильно затягиваются. Попробуйте использовать GROUP BY вместо этого. Либо в подзапросе:

SELECT 
  * 
FROM 
  (
    SELECT 
      "products_displayproduct"."id", 
      "products_displayproduct"."date_created", 
      "products_displayproduct"."date_updated", 
      "products_displayproduct"."name", 
      "products_displayproduct"."sub_title", 
      "products_displayproduct"."tags", 
      "products_displayproduct"."has_multiple_variants", 
      "products_displayproduct"."placement_id", 
      "products_displayproduct"."hidden_placement_category_id", 
      "products_displayproduct"."hidden_placement_super_category_id", 
      "products_displayproduct"."brand_id", 
      "products_displayproduct"."poster_image_id", 
      "products_displayproduct"."rating", 
      "products_displayproduct"."reviews", 
      "products_displayproduct"."is_toppick", 
      "products_displayproduct"."last_amalgamation", 
      "products_displayproduct"."search_index", 
      "products_displayproductaccess"."is_instock" as "subquery_instock", 
      "products_displayproductaccess"."price" as "subquery_price" 
    FROM 
      "products_displayproduct" 
      INNER JOIN "products_displayproductvariant" ON (
        "products_displayproduct"."id" = "products_displayproductvariant"."product_id"
      ) 
      INNER JOIN "products_displayproductaccess" ON (
        "products_displayproductvariant"."id" = "products_displayproductaccess"."product_variant_id"
      ) 
    WHERE 
      (
        "products_displayproductaccess"."location_id" IN (
          608, 65, 610, 69, 999, 72, 92, 79, 81, 84, 
          1045, 89, 601, 954, 603, 1276, 605, 607
        )
      ) 
    GROUP BY 
      "products_displayproduct"."id"
    ORDER BY 
      "products_displayproduct"."id" ASC NULLS LAST, 
      "products_displayproductaccess"."is_instock" DESC NULLS LAST, 
      "products_displayproductaccess"."price" DESC NULLS LAST
  ) as subquery 
ORDER BY 
  "subquery"."subquery_instock" DESC, 
  "subquery"."subquery_price" DESC
LIMIT 10

, либо в основном запросе:

SELECT 
  * 
FROM 
  (
    SELECT 
      "products_displayproduct"."id" as "subquery_id", 
      "products_displayproduct"."date_created", 
      "products_displayproduct"."date_updated", 
      "products_displayproduct"."name", 
      "products_displayproduct"."sub_title", 
      "products_displayproduct"."tags", 
      "products_displayproduct"."has_multiple_variants", 
      "products_displayproduct"."placement_id", 
      "products_displayproduct"."hidden_placement_category_id", 
      "products_displayproduct"."hidden_placement_super_category_id", 
      "products_displayproduct"."brand_id", 
      "products_displayproduct"."poster_image_id", 
      "products_displayproduct"."rating", 
      "products_displayproduct"."reviews", 
      "products_displayproduct"."is_toppick", 
      "products_displayproduct"."last_amalgamation", 
      "products_displayproduct"."search_index", 
      "products_displayproductaccess"."is_instock" as "subquery_instock", 
      "products_displayproductaccess"."price" as "subquery_price" 
    FROM 
      "products_displayproduct" 
      INNER JOIN "products_displayproductvariant" ON (
        "products_displayproduct"."id" = "products_displayproductvariant"."product_id"
      ) 
      INNER JOIN "products_displayproductaccess" ON (
        "products_displayproductvariant"."id" = "products_displayproductaccess"."product_variant_id"
      ) 
    WHERE 
      (
        "products_displayproductaccess"."location_id" IN (
          608, 65, 610, 69, 999, 72, 92, 79, 81, 84, 
          1045, 89, 601, 954, 603, 1276, 605, 607
        )
      ) 
    ORDER BY 
      "products_displayproduct"."id" ASC NULLS LAST, 
      "products_displayproductaccess"."is_instock" DESC NULLS LAST, 
      "products_displayproductaccess"."price" DESC NULLS LAST
  ) as subquery 
GROUP BY 
  "subquery"."subquery_id"
ORDER BY 
  "subquery"."subquery_instock" DESC, 
  "subquery"."subquery_price" DESC
LIMIT 10
...