我有一个完美的查询(original question that has table structure too),但是它会创建一个临时表,由于数据量的原因,这个表很可能需要12秒。 (1表有95k记录,另有155k,另有21k)。
有没有办法绕过临时表解决方案或让它运行得更快?也许建议应该索引哪些字段?我有ID字段,日期字段等...索引,但这根本没有帮助。
SELECT
(
CASE
WHEN a.winner = a.f_a THEN "Win"
WHEN a.winner = a.f_b THEN "Loss"
WHEN a.winner IS NULL THEN a.method
END
) AS result,
SUM(a.f_a IN (d.fighter_a, d.fighter_b) AND d.winner <=> a.f_a) AS fighter_wincount,
SUM(a.f_a IN (d.fighter_a, d.fighter_b) AND d.winner IS NOT NULL AND d.winner <> a.f_a) AS fighter_losscount,
SUM(a.f_a IN (d.fighter_a, d.fighter_b) AND d.method = "Draw") AS fighter_drawcount,
SUM(a.f_a IN (d.fighter_a, d.fighter_b) AND d.method = "No Contest") AS fighter_nocontestcount,
b.name AS opponent,
SUM(a.f_b IN (d.fighter_a, d.fighter_b) AND d.winner <=> a.f_b) AS opponent_wincount,
SUM(a.f_b IN (d.fighter_a, d.fighter_b) AND d.winner IS NOT NULL AND d.winner <> a.f_b) AS opponent_losscount,
SUM(a.f_b IN (d.fighter_a, d.fighter_b) AND d.method = "Draw") AS opponent_drawcount,
SUM(a.f_b IN (d.fighter_a, d.fighter_b) AND d.method = "No Contest") AS opponent_nocontestcount,
b.fighter_id AS opponent_id,
b.fighting_out_of_country AS opponent_country,
a.method AS method,
a.method_type AS method_type,
a.round AS round,
a.time AS time,
c.event_id AS event_id,
c.event_name AS event,
c.event_date AS date,
c.event_city AS event_city,
c.event_state AS event_state,
c.event_country AS event_country
FROM
(
SELECT
fight_id,
IF(fighter_b = :fighter_id_3, fighter_b, fighter_a) AS f_a,
IF(fighter_b = :fighter_id_4, fighter_a, fighter_b) AS f_b,
winner,
method,
method_type,
round,
time,
event
FROM
fights
WHERE
:fighter_id_5 IN (fighter_a, fighter_b)
) a
INNER JOIN
fighters b ON a.f_b = b.fighter_id
INNER JOIN
events c ON a.event = c.event_id
LEFT JOIN
(
SELECT
a.fighter_a,
a.fighter_b,
a.winner,
a.method,
b.event_date
FROM
fights a
INNER JOIN
events b ON a.event = b.event_id
) d ON
(a.f_a IN (d.fighter_a, d.fighter_b) OR a.f_b IN (d.fighter_a, d.fighter_b)) AND
d.event_date <= c.event_date
GROUP BY
a.fight_id
ORDER BY
date DESC
答案 0 :(得分:0)
使用a.id IN (b.a_id, b.b_id)
从不将具有高效性,您将无法创建适合查询的索引。您应该规范化结构的这一方面。
我建议您对架构进行以下更改:
fight_date_time
添加到您的fights
表格fighter_a
和fighter_b
移至参与者表格fight_id
,fighter_id
- 标准化 - 每次战斗两行
以下将为每场战斗创建两个记录(每个战斗机一个),但也会列出他们的对手,以及他们的记录都参加战斗。
SELECT
event.event_name,
event.event_date,
MAX(CASE WHEN participant.fighter_id = fighter.id THEN fighter.name END) AS fighter,
MAX(CASE WHEN participant.fighter_id = fighter.id THEN record.wins END) AS wins,
MAX(CASE WHEN participant.fighter_id = fighter.id THEN record.draws END) AS draws,
MAX(CASE WHEN participant.fighter_id = fighter.id THEN record.losses END) AS losses,
CASE WHEN fight.winner = participant.fighter_id THEN 'Win'
WHEN fight.winner IS NULL THEN 'Draw'
ELSE 'Loss' END AS result,
fight.method,
MAX(CASE WHEN participant.fighter_id <> fighter.id THEN fighter.name END) AS Opp,
MAX(CASE WHEN participant.fighter_id <> fighter.id THEN record.wins END) AS Opp_wins,
MAX(CASE WHEN participant.fighter_id <> fighter.id THEN record.draws END) AS Opp_draws,
MAX(CASE WHEN participant.fighter_id <> fighter.id THEN record.losses END) AS Opp_losses
FROM
event
INNER JOIN
fight
ON event.id = fight.event_id
INNER JOIN
participant
ON participant.fight_id = fight.id
INNER JOIN
(
SELECT
participant.fighter_id,
participant.fight_id,
SUM(CASE WHEN prevFight.winner = participant.fighter_id THEN 1 ELSE 0 END) AS wins,
SUM(CASE WHEN prevFight.winner IS NULL) AS draws,
SUM(CASE WHEN prevFight.winner <> participant.fighter_id THEN 1 ELSE 0 END) AS losses
FROM
participant
INNER JOIN
fight
ON participant.fight_id = fight.id
INNER JOIN
participant AS prevParticipant
ON prevParticipant.fighter_id = participant.fighter_id
INNER JOIN
fight AS prevFight
ON prevFight.id = prevParticipant.fight_id
AND prevFight.fight_date_time < fight.fight_date_time
GROUP BY
participant.fighter_id,
participant.fight_id
)
AS record
ON record.fight_id = participant.fight_id
INNER JOIN
fighter
ON fighter.id = record.fighter_id
GROUP BY
event.id,
fight.id,
participant.fighter_id
如果您只想查看一架战斗机的结果,请添加:
- WHERE participant.fighter_id = :fighter_id
更好的是,使用触发器保持此类数据的最新状态。这样你就不需要一次又一次地计算它。