Из MSDN, Math.Round (double a) возвращает:
Целое число, ближайшее к a. Если дробный компонент а находится посередине между двумя целыми числами, одно из которых является четным, а другое нечетным, то возвращается четное число.
... и так, 2.5, будучи на полпути между 2 и 3, округляется до четного числа (2). это называется Банковским округлением (или округлением до четного) и является широко используемым стандартом округления.
Та же статья MSDN:
Поведение этого метода соответствует стандарту IEEE 754, раздел 4. Этот вид округления иногда называют округлением до ближайшего или округлением банкира. Он сводит к минимуму ошибки округления, возникающие в результате последовательного округления значения средней точки в одном направлении.
Вы можете указать другое поведение округления, вызвав перегрузки Math.Round, которые принимают режим MidpointRounding
.
SELECT id, name, last_reply, replies
FROM (
SELECT topic_id, MAX(date) AS last_reply, COUNT(*) AS replies
FROM wp_pod_tbl_forum
GROUP BY
topic_id
) r
JOIN wp_pod_tbl_forum t
ON t.topic_id = 0
AND t.id = r.topic_id
UNION ALL
SELECT id, name, date, 0
FROM wp_pod_tbl_forum t
WHERE NOT EXISTS
(
SELECT NULL
FROM wp_pod_tbl_forum r
WHERE r.topic_id = t.id
)
AND t.topic_id = 0
ORDER BY
date DESC
LIMIT 0, 20
Если ваша таблица MyISAM
или id
не является ПЕРВИЧНЫМ КЛЮЧОМ
, вам необходимо создать составной ондекс на (topic_id, id)
.
Если ваша таблица - InnoDB
, а id
- это ПЕРВИЧНЫЙ КЛЮЧ
, индекс только на ] (topic_id)
подойдет ( id
будет неявно добавлен в индекс).
Обновление
Этот запрос, скорее всего, будет еще более эффективным, если у вас есть индексы на (topic_id, id)
и (date, id)
:
Подробнее о производительности см. В этой статье в моем блоге:
Этот запрос завершается через 30 мс
для 100 000
строк выборки данных:
SELECT id, name, last_reply,
(
SELECT COUNT(*)
FROM wp_pod_tbl_forum fc
WHERE fc.topic_id = fl.topic_id
) AS replies
FROM (
SELECT topic_id, date AS last_reply
FROM wp_pod_tbl_forum fo
WHERE id = (
SELECT id
FROM wp_pod_tbl_forum fp
WHERE fp.topic_id = fo.topic_id
ORDER BY
fp.date DESC, fp.id DESC
LIMIT 1
)
AND fo.topic_id <> 0
ORDER BY
fo.date DESC, fo.id DESC
LIMIT 20
) fl
JOIN wp_pod_tbl_forum ft
ON ft.id = fl.topic_id
UNION ALL
SELECT id, name, date, 0
FROM wp_pod_tbl_forum t
WHERE NOT EXISTS
(
SELECT NULL
FROM wp_pod_tbl_forum r
WHERE r.topic_id = t.id
)
AND t.topic_id = 0
ORDER BY
last_reply DESC, id DESC
LIMIT 20
Оба индекса необходимы для того, чтобы этот запрос был эффективным.
Если ваша таблица - InnoDB
и id
- это ПЕРВИЧНЫЙ КЛЮЧ
, то вы можете опустить id из индексов
выше.
Вы можете разбить его на набор подзапросов (как внутренние запросы). Мне нужна схема, чтобы по-настоящему играть, но если вы
SELECT t.id, t.name, MAX(COALESCE(r.date, t.date)) AS date, COUNT(r.id) AS replies
FROM (
SELECT (id, name, date)
FROM wp_pod_tbl_forum
WHERE topic_id = 0
) as t
LEFT OUTER JOIN
wp_pod_tbl_forum r
WHERE
r.topic_id = t.id
GROUP BY
t.id
ORDER BY
date DESC LIMIT 0,20;
, это может немного ускорить ее, это может быть даже не лучший ответ (могут существовать ошибки).
Есть множество способов сделать это, но самое важное, что нужно сделать при настройке SQL, - это максимально уменьшить каждый набор перед выполнением операции.