Получение последней цены от конкретного продукта в MYSQL (быстрее, чем это)

#mysql #max

#mysql #max

Вопрос:

Я беру последнюю цену от конкретного продукта, но производительность действительно низкая для более чем 3 миллионов цен.

У кого-нибудь есть лучший способ сделать это? Мой сервер загружается этим медленным запросом.

prices.id используется для хранения идентификатора магазина в prices таблице, чтобы я мог объединить его с stores.id из stores таблицы.

 SELECT prices.id, prices.price, prices.timelog, prices.user_id FROM prices
WHERE prices.id IN (SELECT stores.id FROM stores WHERE city = "miami" )
AND prices.product_id = 1
AND prices.timelog IN 
  (SELECT MAX( lastprice.timelog ) 
   FROM prices AS lastprice 
   WHERE lastprice.id = prices.id AND lastprice.product_id = 1)
  

Комментарии:

1. Не могли бы вы, пожалуйста, показать нам индексы, которые у вас есть в таблице prices и stores ?

Ответ №1:

Не видя структуры таблиц, я думаю, вы могли бы сделать:

 select * from prices
join stores on stores.id = prices.id
where stores.city = 'miami' and prices.product = 1
 order by timelog DESC LIMIT 1
  

Комментарии:

1. У MySQL top 1 было бы LIMIT 1 в конце AFAIK.

2. @Richard, очень хорошая компактная переписать

3. @caio, используй ответ Ричарда и убедись, что stores.id и prices.id являются первичными ключами для этих таблиц. Также убедитесь, что у вас есть индекс на timelog , stores.city и на prices.product .

4. @Johan: prices.id не похоже на первичный ключ. Возможно, его лучше переименовать в prices.storeid .

5. @ypercube, теперь, когда вы упомянули об этом, это действительно выглядит как странное объединение, может ли это быть причиной join using ... заболевания?

Ответ №2:

3 миллиона цен могут означать, что ваше приложение может извлечь выгоду из некоторой денормализации. (т. Е. Каким-либо образом отметьте последнюю цену, помните: запись-один раз, чтение-много часто стоит накладных расходов на более медленную запись).

С текущими данными стоит попробовать:

 SELECT p1.id, p1.price, p1.timelog, p1.user_id 
FROM prices p1
JOIN stores 
ON stores.id = prices.id
AND stores.city = "miami"
LEFT JOIN prices p2
ON p2.product_id = p1.product_id
AND p2.id = p1.id
AND p2.timelog > p1.timelog
WHERE p1.product_id = 1 AND p2.id IS NULL;
  

… и еще один немного более быстрый вариант, который всегда ускользает от меня в это время ночи 🙂

Имейте в виду, что многое может измениться с правильными индексами в таблицах, поэтому, во что бы то ни стало, запустите EXPLAIN для лота.

Комментарии:

1. потрясающе, это было в 4,5 раза быстрее, чем оригинал.

Ответ №3:

Попробуйте это тоже:

 SELECT prices.id
     , prices.price
     , prices.timelog
     , prices.user_id

FROM prices
    JOIN
      ( SELECT MAX( timelog ) AS lasttimelog
        FROM prices 
        WHERE product_id = 1
      ) AS lastprice
        ON prices.timelog = lastprice.lasttimelog

WHERE EXISTS
    ( SELECT * 
      FROM stores
      WHERE prices.id = stores.id
        AND stores.city = "miami"
    )
  AND prices.product_id = 1
  

Я бы предположил, что индекс в (id,product_id,timelog) in products и индекс в id или (city,id) в таблице stores помогут ускорить запрос.

Было бы лучше, если бы вы запускали EXPLAIN для запросов, а также публиковали структуру таблиц (поля, индексы, ссылки).