【问题标题】:Can anyone work out a more optimised SQL solution?任何人都可以制定出更优化的 SQL 解决方案吗?
【发布时间】:2011-01-05 00:34:21
【问题描述】:

我担心这有点贵。

另外,我很快就会为标签实现一个标准化系统,因此会有额外的连接。

除此之外,我有 4 个表(tbl_videos、tbl_articles、tbl_galleries 和 tbl_users),我想显示每个表的三个结果,因此必须在按一下“搜索”时运行四次查询。

SELECT *, 
(
(CASE WHEN `description` LIKE '%hotel%' THEN 1 ELSE 0 END) + 
(CASE WHEN `description` LIKE '%london%' THEN 1 ELSE 0 END) + 
(CASE WHEN `description` LIKE '%lazy%' THEN 1 ELSE 0 END) + 
(CASE WHEN `description` LIKE '%dog%' THEN 1 ELSE 0 END) +

(CASE WHEN `title` LIKE '%hotel%' THEN 1 ELSE 0 END) + 
(CASE WHEN `title` LIKE '%london%' THEN 1 ELSE 0 END) + 
(CASE WHEN `title` LIKE '%lazy%' THEN 1 ELSE 0 END) + 
(CASE WHEN `title` LIKE '%dog%' THEN 1 ELSE 0 END) +

(CASE WHEN `tags` LIKE '%hotel%' THEN 1 ELSE 0 END) + 
(CASE WHEN `tags` LIKE '%london%' THEN 1 ELSE 0 END) + 
(CASE WHEN `tags` LIKE '%lazy%' THEN 1 ELSE 0 END) + 
(CASE WHEN `tags` LIKE '%dog%' THEN 1 ELSE 0 END)

) AS relevance
FROM `table`
WHERE `description` LIKE '%hotel%'
  OR `description` LIKE '%london%'
  OR `description` LIKE '%lazy%'
  OR `description` LIKE '%dog%' 
  OR `title` LIKE '%hotel%'
  OR `title` LIKE '%london%'
  OR `title` LIKE '%lazy%'
  OR `title` LIKE '%dog%'
  OR `tags` LIKE '%hotel%'
  OR `tags` LIKE '%london%'
  OR `tags` LIKE '%lazy%'
  OR `tags` LIKE '%dog%'
ORDER BY relevance DESC
LIMIT 0 , 3;

【问题讨论】:

  • 您要解决的问题是什么,是否只是在数据库中搜索给定的搜索词?过程是什么,你让用户在搜索框中输入数据,然后会发生什么?
  • 它只是一个标准搜索,是的。然后像 facebook 一样显示每个类别的 x 个列表;在我的例子中,结果显示了 3 个用户、3 篇文章、3 个视频和 3 个画廊。
  • 所以在您的示例中,用户搜索了“hotel london lazy dog”?
  • 是的....,我知道奇怪的搜索。大声笑

标签: mysql optimization search query-optimization


【解决方案1】:

是的,这可能会非常消耗资源,但听起来您在提交查询之前前面有一个业务层。

想想你想要实现什么,以及你可以自己做些什么,比如解析搜索词,甚至为用户提供描述、标题和标签的单独字段,并适当地构造查询,以更直接地查询,而不是有效地说,“我有一些数据与此搜索词非常相似,在此表的列中的某处”。

一旦你确定了你的业务逻辑(如果上面的查询是如何结束的,虽然我对此表示怀疑,那么尽管如此),那么你绝对应该通过解释计划运行查询,看看你可能会从哪里开始一些索引来帮助数据库。

编辑:

好的,这个建议怎么样

select matched_val, relevance from (
    select description as matched_val, count(*) as relevance
    from table 
    where description like '%hotel%'
    or description like '%london%'
    or description like '%lazy%'
    or description like '%dog%'
    group by description

    union all

    select title as matched_val, count(*) as relevance
    from table 
    where title like '%hotel%'
    or title like '%london%'
    or title like '%lazy%'
    or title like '%dog%'
    group by title

    union all

    select tags as matched_val, count(*) as relevance
    from table 
    where tags like '%hotel%'
    or tags like '%london%'
    or tags like '%lazy%'
    or tags like '%dog%'
    group by tags
) as a
order by a.relevance desc
LIMIT 0 , 3

这至少意味着您只需要进行一次类似的匹配,而不是在谓词和 switch 语句中,而且优化器将能够在描述、标题和标签上使用索引(您需要添加你自己),你应该离开。

试一试,看看您的查询优化器喜欢它...

【讨论】:

  • 嗯,我收到以下错误“每个派生表都必须有自己的别名”:S 否则看起来不错
  • 查看我的最新编辑以获取更多格式的版本...您可能需要执行以下操作:选择matched_val,相关性(--all those unions)作为 a.relevance desc 限制的顺序0, 3 我没用过mysql,但你得在sql server上做
  • 哇...没有错误,但与 0.0006 相比,20 行的 0.0554 秒要贵得多,而且结果是错误的。我认为我不能更高效,因为每个子查询都是一个查询,因此它的 4 个查询而不是一个大查询。还是谢谢你。
  • 有趣,哦,好吧,我们试过了!...我绝对建议比较两个查询的查询计划,但看看它是如何做到的...但是是的,只有一个查询看起来像它一次扫描表/索引会更有效,而不是三个单独的。
  • 再次感谢。我认为我的解决方案是您的第一个建议,让用户在搜索时从组合框中选择一个类别,以便我使用原始查询,但每次搜索只使用一次。
猜你喜欢
  • 2019-04-24
  • 1970-01-01
  • 2010-09-30
  • 1970-01-01
  • 2020-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多