Каков эквивалент Ruby ActiveRecord для этого SQL?

Что было бы оптимизированным (быстрым) эквивалентом ActiveRecord в Ruby:

SELECT DISTINCT customers.city 
FROM customers
INNER JOIN (
  SELECT c_id 
  FROM carts
  WHERE shop_id = #{`shop_id`}
  ORDER BY created_at DESC 
  LIMIT 1000 OFFSET 1000
) AS filtered_carts ON customers.id = filtered_carts.c_id;

Примечание. shop_id — это рубиновая переменная, передаваемая в запрос/ассоциацию. Спасибо

Этот приведенный выше SQL работает так быстро, как ожидалось.

Я пытаюсь найти чистое решение ActiveRecord, чтобы избежать чего-то подобного:

customers = Customer
  .select(:city)
  .distinct
  .joins("
    INNER JOIN (
      SELECT c_id
      FROM carts
      WHERE shop_id = #{`shop_id`}
      ORDER BY created_at DESC
      LIMIT 1000 OFFSET 1000
    ) AS filtered_carts
    ON customers.id = filtered_carts.c_id
  ")

Причина в том, чтобы избежать жестко запрограммированного SQL в ActiveRecord, чтобы предотвратить возможные будущие проблемы с обратной совместимостью возможных изменений и миграций модели...

Зачем ты это делаешь OFFSET 1000?

jarlh 30.03.2023 09:01

Было просто произвольно демонстрировать попытку разделить работу на множество частей (offset и limit). Я пытаюсь найти решение как для тысячи, так и для миллиона записей.

Da V 30.03.2023 09:46
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
3
58
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я думаю, что вам вообще не нужен JOIN. Подзапроса в where должно быть достаточно:

customer_ids = 
  Cart
    .select(:c_id)
    .where(shop_id: shop_id)
    .order(:created_at)
    .limit(1000)
    .offset(1000)

Customer
  .where(id: customer_ids)
  .distinct
  .pluck(:city)

Обратите внимание, что customer_ids — это всего лишь ActiveRecord::Relation и что запрос не выполняется немедленно. Он запускается как подзапрос только при выполнении второго запроса.

Спасибо - один вопрос - если у вас более 1 миллиона записей о клиентах, как это повлияет на производительность Ruby/ActiveRecord (передача хэша, строки или массива с таким количеством записей)? Это подразумевает удаление offset и limit из запроса.

Da V 30.03.2023 09:44

Это зависит от многих факторов: спецификации сервера базы данных, насколько хорошо установлены индексы в таблицах базы данных, памяти вашего сервера приложений, насколько велики записи. Поэтому я не могу дать хороший ответ на этот вопрос. Вы просто должны попробовать это. В общем, подзапрос, вероятно, более эффективен, чем объединение, но чем больше записей соответствует запросу, тем медленнее будет ответ, тем больше памяти потребуется серверам для выполнения запроса.

spickermann 30.03.2023 10:07

@spickermann будет ли WHERE EXIST(...) быстрее, чем WHERE "customers"."id" IN(...)?

max 30.03.2023 14:07

@max Просто быстро изучил эту тему. И похоже, что это зависит от размера подзапроса и от конкретной реализации в базе данных.

spickermann 30.03.2023 14:56

Другие вопросы по теме