我正在使用H2,我有一个书籍数据库(表条目)和作者(表人员),通过多对多关系连接,本身存储在表Authorship中。 数据库相当大(900'000 +人和2.5M +书)。
我正在尝试有效地选择由至少一位名称与模式匹配的作者(LIKE'%pattern%')创作的所有书籍的列表。这里的诀窍是模式应该严格限制匹配作者的数量,每个作者都有相当少量的相关书籍。
我尝试了两个问题:
SELECT p.*, e.title FROM (SELECT * FROM Persons WHERE name LIKE '%pattern%') AS p
INNER JOIN Authorship AS au ON au.authorId = p.id
INNER JOIN Entries AS e ON e.id = au.entryId;
和
SELECT p.*, e.title FROM Persons AS p
INNER JOIN Authorship AS au ON au.authorId = p.id
INNER JOIN Entries AS e ON e.id = au.entryId
WHERE p.name like '%pattern%';
我预计第一个会快得多,因为我正在加入一个更小的(子)作者表,但是他们都需要花费很长时间。事实上,我可以手动将查询分解为三个选项,然后更快地找到我想要的结果。
当我尝试EXPLAIN查询时,我发现它们确实非常相似(表上的完全连接,只有WHERE子句),所以我的问题是:如何实现快速选择,依赖于作者的过滤器应该导致与其他两个表的连接小得多吗?
请注意,我尝试使用MySQL进行相同的查询,并得到符合我预期的结果(首先选择更快)。
谢谢。
答案 0 :(得分:1)
好的,这件事最终对我有用。
而不是运行查询:
SELECT p.*, e.title FROM (SELECT * FROM Persons WHERE name LIKE '%pattern%') AS p
INNER JOIN Authorship AS au ON au.authorId = p.id
INNER JOIN Entries AS e ON e.id = au.entryId;
......我跑了:
SELECT title FROM Entries e WHERE id IN (
SELECT entryId FROM Authorship WHERE authorId IN (
SELECT id FROM Persons WHERE name LIKE '%pattern%'
)
)
它不是完全相同的查询,因为现在我没有将作者ID作为结果中的列,但这样做我想要的:利用模式限制的事实作者的数量非常小,只能通过少量条目进行搜索。
有趣的是,这对于H2来说效果很好(比连接快得多),但是对于MySQL来说它非常慢。 (这与LIKE'%pattern%'部分无关,请参阅其他答案中的注释。)我认为查询的优化方式不同。
答案 1 :(得分:0)
SELECT * FROM Persons WHERE name LIKE '%pattern%'
总是会在900,000+行表上使用LONG,因为当你的模式'%pattern%'
以%
MySql开头时,不能使用任何索引而应该这样做全表扫描。你应该研究full-text indexes and function。
答案 2 :(得分:0)
好吧,因为类似条件以通配符开头,所以会导致全表扫描总是很慢,不会发生内部缓存。
如果你想进行全文搜索,mysql不是你最好的选择。查看其他软件(例如solr)来解决此类问题。