[英]How can I speed up a mysql query? 2 joins, 3 text conditions, ~3,000k records
这是我的查询:
SELECT distinct decks.deckid, tmnt.tournamentid, tmnt.tournamentname,
cast(concat(Monthname(tournamentdate),' ',day(tournamentdate),', ',
year(tournamentdate)) as char) as ConfiguredTournamentDate,
tournamentdate, decks.pilot, decks.deckname, decks.record
FROM tournaments tmnt
LEFT JOIN decks on decks.tournamentid = tmnt.tournamentid
LEFT JOIN cardsindeck cid on cid.deckid = decks.deckid
WHERE upper(decks.deckname) like '%JULIAN23%'
OR upper(decks.pilot) like '%JULIAN23%'
OR upper(cid.cardname) like '%JULIAN23%'
ORDER BY tournamentdate desc;
此查询返回 12 个结果,可能为 44K。
我已经建立了 FULLTEXT 索引(我将包括下面的解释)。 这个查询需要 3-6 秒,考虑到我猜的记录,这还不错,但我想看看我能做些什么来让它更快。 数据每天只更新一次,我可以在某个地方建立一个临时表并查询它吗?
我没有比这更好的方法了,基本上我想看看有没有其他方法我可以在这里使用。
解释:
1 SIMPLE tmnt ALL 2772 Using temporary; Using filesort
1 SIMPLE decks ref TourneyID_idx TourneyID_idx 5 magic_decks_july.tmnt.TournamentID 12
1 SIMPLE cid ref DeckID_idx DeckID_idx 5 magic_decks_july.decks.DeckID 24 Using where; Distinct
更新
这将查询减少到 5 秒。 Muuuuuch 更容易接受。 现在深入研究其他 3 个问题领域...... :)
SELECT distinct decks.deckid, tmnt.tournamentid, tmnt.tournamentname,
cast(concat(Monthname(tournamentdate),' ',day(tournamentdate),',
',year(tournamentdate)) as char) as ConfiguredTournamentDate, tournamentdate,
decks.pilot, decks.deckname, decks.record
from tournaments tmnt
inner join decks on decks.tournamentid = tmnt.tournamentid
where decks.deckname like '%CONDESCEND%'
OR decks.pilot like '%CONDESCEND%'
UNION ALL
SELECT distinct decks.deckid, tmnt.tournamentid, tmnt.tournamentname,
cast(concat(Monthname(tournamentdate),' ',day(tournamentdate),',
',year(tournamentdate)) as char) as ConfiguredTournamentDate, tournamentdate,
decks.pilot, decks.deckname, decks.record
from cardsindeck cid
left join decks on cid.deckid = decks.deckid
left join tournaments tmnt on decks.tournamentid = tmnt.tournamentid
where cid.cardname like '%CONDESCEND%'
order by tournamentdate
如果您重写查询以在连接语句中进行过滤,看起来您会得到更好的结果。
例子,
SELECT *
FROM (select now() query_time) qt
INNER JOIN table_with_3mil_rows t1 ON value rlike "test"
INNER JOIN smaller_table t2 ON value rlike "test"
当前查询时间的子选择背后的原因有两个。 防止查询缓存,并允许您在结果集构建开始时进行最多的过滤,它可以发挥最大的作用。
Mysql 逐表构建查询,因此当它打开第一个表进行读取时,它会拉入除 ON 子句过滤掉的所有行之外的所有行。 然后它读入下一个表,过滤掉不能正确连接的东西,并将它们添加到表中,直到连接完成。
然后它执行 where 子句要求的过滤。
如果你重新排序它以便它在你的牌组名称上过滤,你会减小 memory 中表的大小,从而加快查询速度。
我还建议在您的卡片表上使用分区。 在 300 万条记录中,这是巨大的。 对甲板 ID 进行分区会有所帮助
添加
...
LIMIT 12
...我还认为,如果数据每天仅更新一次,则使用预先计算的结果创建一个专用表是一个极好的和最简单的解决方案。 每次更新数据并执行普通 SELECT * FROM CACHED_DATA
时,只需重新计算您的表;
您的问题是使用UPPER
- 它在每行的 where 子句中调用,这非常昂贵
在 mysql 中, like
是不区分大小写的,因此使用UPPER
对查询没有影响。
尝试这个:
SELECT distinct decks.deckid, tmnt.tournamentid, tmnt.tournamentname,
cast(concat(Monthname(tournamentdate),' ',day(tournamentdate),', ',
year(tournamentdate)) as char) as ConfiguredTournamentDate,
tournamentdate, decks.pilot, decks.deckname, decks.record
FROM tournaments tmnt
LEFT JOIN decks on decks.tournamentid = tmnt.tournamentid
LEFT JOIN cardsindeck cid on cid.deckid = decks.deckid
WHERE decks.deckname like '%julian23%' -- Removed upper() usage
OR decks.pilot like '%julian23%' -- Removed upper() usage
OR cid.cardname like '%julian23%' -- Removed upper() usage
ORDER BY tournamentdate desc;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.