【问题标题】:SQL for search query with multiple table join用于具有多个表连接的搜索查询的 SQL
【发布时间】:2017-06-12 12:20:51
【问题描述】:

我有以下表格

文档

  • docid (PK)
  • 网址

wdata

  • wordid (PK)

标题

  • wordid
  • 文档

(wordid & docid 组合唯一)

wurl

  • wordid
  • 文档

(wordid & docid 组合唯一)

为了搜索任何短语,我将其分解为单词并获取其wordid。表wtitle,wurl 将用于对行进行评分以进行排名。我打算添加更多用于评分的表,例如 inlink 、 inh1 标记等。但是我在为搜索词构建我的 sql 查询时遇到问题。

我的 SQL 查询是这样的

SELECT d.docid,furl,IF(t.wordid IS NULL,0,1) AS intitle,IF(u.wordid IS NULL,0,1) AS inurl FROM document d
LEFT JOIN wtitle t ON t.docid=d.docid
LEFT JOIN wdata w ON w.wordid=t.wordid
LEFT JOIN wurl u ON u.wordid=w.wordid AND u.docid=d.docid
WHERE w.wordid IN (wordid1,wordid2,wordid3)

我有以下疑问

  1. 如何检查每个表 wtitlewurl 两者甚至更多,因为目前它正在搜索 wtitle 中的第一个,因为 LEFT JOIN 并且其他连接被忽略了?
  2. 如何正确地构建这个 SQL 查询?

    SQL 小提琴http://sqlfiddle.com/#!9/ab0052/4/0

Wordid 3 在 URL 中,但不在 Docid 2 的标题中

Wordid 3 不在 URL 中,而是在 Docid 3 的标题中

我想同时返回 doc 2 和 3,但是因为它首先通过 wtitle 连接它忽略(使用第一个查询数据)其他连接

【问题讨论】:

标签: php sql join


【解决方案1】:

如果您想知道,比如说,您要查找的两个词是否出现在文档中both,您必须同时查看标题和 url。 (否则,如果您知道其中一个词存在于 title 中,而一个词存在于 url 中,您将不知道它是同一个词还是两个词。)所以首先将两个表与UNION ALL 结合起来,但要记住属于哪条记录到哪张桌子。然后我们可以计算组合和每个位置(标题或网址)。

这是一个查找单词 ID 3 和 4 的查询。它首先列出与这两个单词匹配的条目,然后是只有一个单词匹配的文档:

SELECT 
  d.docid, 
  d.furl, 
  w.cnt_combined,
  w.cnt_in_title,
  w.cnt_in_url
FROM document d
JOIN
(
  select
    docid,
    count(distinct wordid) cnt_combined,
    sum(place = 'TITLE') cnt_in_title,
    sum(place = 'URL') cnt_in_url
  from
  (
    select 'TITLE' as place, docid, wordid from wtitle where wordid in (3,4)
    union all
    select 'URL' as place, docid, wordid from wurl where wordid in (3,4)
  ) both_tables
  group by docid
) w ON w.docid = d.docid
order by w.cnt_combined desc;

您可以通过替换来查找单词而不是单词 ID

where wordid in (3,4)

通过

where wordid in (select wordid from wdata where word in ('vaccination', 'the'))

Rextester 链接:http://rextester.com/KPVX67861(SQL fiddle 大部分时间都对我不起作用。)

我建议这些覆盖索引:

CREATE INDEX idx_wtitle ON wtitle(wordid, docid);
CREATE INDEX idx_wurl ON wurl(wordid, docid);

首先使用wordid,DBMS 可以轻松找到条目,并且由于docid 已经在索引中,DBMS 不必访问表。它从索引中获取所有数据。 (这就是为什么它们被称为覆盖索引;它们覆盖了查询需要的所有列。)

【讨论】:

  • 哇,非常感谢,我真的很喜欢 place 的别名并加上总和,它确实给了我一些想法,但是你的 SQL 查询没有正确使用索引,对我来说有 10 wdata 表和大型 wdoc 表中的百万数据执行此搜索查询需要几分钟。由于您使用的是UNION,因此我将 WHERE 条件转移到内部以获得更好的性能!更接近我想要的东西!也许我可以用许多积分表做 UNION ALL 并总结以获得分数或计数!谢谢你的帮助!
  • 是的,将 WHERE 子句移入内部并将其直接应用于表是一个好主意。 (我已经习惯了 Oracle,其出色的优化器在内部执行此操作,因此我不必两次编写相同的条件。似乎我有点被宠坏了 ;-) 我建议使用以下两个索引来运行此操作尽快:wtitle(wordid, docid)wurl(wordid, docid)。在这些索引中将wordid 放在首位很重要,这样可以快速找到它们。 DBMS 甚至不再需要读取表,因为它直接从索引中获取docid
猜你喜欢
  • 1970-01-01
  • 2018-04-03
  • 2019-03-28
  • 1970-01-01
  • 2021-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-05
相关资源
最近更新 更多