MySQL - несколько запросов или один запрос - PullRequest
0 голосов
/ 30 мая 2020

Итак, у меня есть таблица с голосами. Соответствующие столбцы для этой проблемы: user и timestamp.

Мне нужно получить общее количество голосов пользователя, а также их голоса в этом месяце .

Я знаю вопросы - я не прошу их. Я использую их одновременно:

Голосов в этом месяце / Всего голосов:

SELECT COUNT( 0 ) FROM votes WHERE ( timestamp BETWEEN DATE_FORMAT( NOW( ) ,'%Y-%m-01' ) AND NOW( ) ) AND user = ?;

SELECT COUNT( 0 ) FROM votes WHERE user = ?;

На данный момент моя база данных недостаточно велика (или даже не достаточно запрошена), чтобы обеспечить производительность это проблема. Однако вскоре это изменится. Следует ли мне хранить запросы отдельно или я должен:

SELECT COUNT( 0 ) AS totalVotes,
       SUM( IF( timestamp BETWEEN DATE_FORMAT( NOW( ) ,'%Y-%m-01' )
                              AND NOW( ), 1, 0 ) ) AS votesThisMonth
    FROM votes WHERE user = ?;

Каков наилучший метод? Есть ли какие-нибудь советы по запросу нескольких бит информации из одной и той же таблицы, чтобы избежать необходимости искать ее дважды? Является ли мой комбинированный запрос тем, что мне следует использовать ?

Спасибо!

Ответы [ 3 ]

2 голосов
/ 30 мая 2020

Я бы порекомендовал второе решение, в котором используется уникальный запрос с условной суммой.

Обоснование: для создания второго набора результатов вам необходимо отсканировать подмножество первого набора результатов . Так что необходимая дополнительная обработка в любом случае довольно крошечная. С другой стороны, выполнение двух отдельных запросов включает еще одно обращение к серверу, еще один синтаксический анализ запроса для планировщика запросов и дополнительное сканирование таблицы.

Для повышения производительности вам нужен индекс на (user, timestamp).

1 голос
/ 31 мая 2020

Немного отличается, не обязательно быстрее, чем другие предложения:

SELECT COUNT(*) AS total,
       SUM(LEFT(timestamp, 7) = LEFT(NOW(), 7)) AS this_month
    FROM tbl
    WHERE user_id = ?

И иметь

INDEX(user_id, timestamp) -- in this order.  ("Covering")

Вернемся к вопросу о запросах типа 1 vs 2:

  • Мой комбинированный запрос выполняет одно сканирование всех строк для пользователя.
  • Для запроса «total» также требуется одно сканирование всех строк для пользователя.
  • Запрос «за этот месяц», при использовании BETWEEN или >= в этом месяце выполняется сканирование только строк для пользователя. (Мой не может этого сделать, но это не имеет значения.)
1 голос
/ 30 мая 2020

В MySQL я бы порекомендовал:

SELECT COUNT(*) AS totalVotes,
       SUM(EXTRACT(YEAR_MONTH FROM timestamp) = EXTRACT(YEAR_MONTH FROM NOW())) AS votesThisMonth
FROM votes
WHERE user = ?;

Альтернативой приведенному выше является:

 SUM(timestamp >= CURRENT_DATE - (DAY(CURRENT_DATE) - 1) DAY)

Я настоятельно не рекомендую вам использовать строки для дат, если вы действительно должен. Существует несколько способов получить значения из текущей даты, которые НЕ включают явное или неявное преобразование значения даты / времени в строку.

Кроме того, IF() является избыточным. MySQL позволяет вам просто складывать логические значения. Ни один из них не является стандартным SQL, так что вы можете использовать более сжатую версию.

COUNT(0) меня раздражает. Хотя работает, COUNT(*) или COUNT(1) кажутся проще.

...