重新审视 MySQL 多重匹配查询......需要很长时间

发布于 2024-09-15 02:16:40 字数 1868 浏览 10 评论 0原文

我正在修改几天前的问题。重写了我的查询。

有人可以告诉我为什么使用我将在下面发布的查询在多个表上运行任何类型的查询需要这么长时间?

有人有时间帮我解决这个问题吗?我可以支付 200 美元,我认为这对于两个小时的工作来说已经足够了。我会把答案贴在这里,这样对大家都有好处。

该查询基本上是这样的:

SELECT bb_business.business_name, bb_business.id AS bid FROM bb_business
LEFT JOIN bb_offers       ON bb_business.id   = bb_offers.store_id
LEFT JOIN bb_cat_business ON bb_business.id   = bb_cat_business.store_id
LEFT JOIN bb_categories   ON bb_categories.id = bb_cat_business.cat_id
WHERE bb_business.active = '1'
  AND MATCH(bb_business.business_name)   AGAINST ('zebra')
  OR  MATCH(bb_categories.category_name) AGAINST ('zebra')
  OR  MATCH (bb_business.city,bb_business.state,bb_business.zip) AGAINST ('zebra')
GROUP BY bb_business.business_name
ORDER BY bb_business.business_name DESC
LIMIT 1,10

该查询第一次执行需要 50 秒。第二次就如预期的那样快了。

如果我将该查询更改为仅使用一个“匹配”,速度会很快。一旦我添加第二个 MATCH 或 LIKE 语句,执行时间就会恢复到 40-60 次。

运行该确切的查询运行于:MySQL 返回一个空结果集(即零行)。 (查询花费了 47.7614 秒)

解释返回以下内容:

1 SIMPLE bb_business ALL NULL NULL NULL NULL 2877 Using temporary; Using filesort 
1 SIMPLE bb_offers ALL NULL NULL NULL NULL 94   
1 SIMPLE bb_cat_business ALL NULL NULL NULL NULL 5697   
1 SIMPLE bb_categories eq_ref PRIMARY PRIMARY 8 buxback_site.bb_cat_business.cat_id 1 Using where 

当仅使用一个匹配时,查询使用我在 bb_business 上的全文索引。当我有多个匹配项时,它似乎没有使用任何索引。

这是 bb_business 上的索引:

PRIMARY  PRIMARY 2877       id  
store_id  UNIQUE 2877       store_id  
index_business_name  INDEX 2877       business_name  
business_name  FULLTEXT 1       business_name  
city  FULLTEXT 1       city  
state  
zip  

这是 bb_categories 上的索引:

PRIMARY  PRIMARY 15       id  
category_name  UNIQUE None       category_name  
category_name_2  FULLTEXT None       category_name 

我很绝望!

感谢!

I'm revising my question from a few days ago. Rewrote my query.

Can someone tell me why running any kind of query on multiple tables takes so long using the query I'll post below?

Is there anyone that has time to help me out with this? I can pay $200.00 I figure that's good for two hours of work. I'll post the answer back on here so it will benefit everyone.

The query is basically this:

SELECT bb_business.business_name, bb_business.id AS bid FROM bb_business
LEFT JOIN bb_offers       ON bb_business.id   = bb_offers.store_id
LEFT JOIN bb_cat_business ON bb_business.id   = bb_cat_business.store_id
LEFT JOIN bb_categories   ON bb_categories.id = bb_cat_business.cat_id
WHERE bb_business.active = '1'
  AND MATCH(bb_business.business_name)   AGAINST ('zebra')
  OR  MATCH(bb_categories.category_name) AGAINST ('zebra')
  OR  MATCH (bb_business.city,bb_business.state,bb_business.zip) AGAINST ('zebra')
GROUP BY bb_business.business_name
ORDER BY bb_business.business_name DESC
LIMIT 1,10

That query takes 50 seconds to execute the first time. The second time it's fast as would be expected.

If I alter that query to only use one Match Against, it is fast. As soon as I add a second MATCH or LIKE statement, it's back up to 40-60 execution times.

Running that exact query runs at: MySQL returned an empty result set (i.e. zero rows). (Query took 47.7614 sec)

Explain returns this:

1 SIMPLE bb_business ALL NULL NULL NULL NULL 2877 Using temporary; Using filesort 
1 SIMPLE bb_offers ALL NULL NULL NULL NULL 94   
1 SIMPLE bb_cat_business ALL NULL NULL NULL NULL 5697   
1 SIMPLE bb_categories eq_ref PRIMARY PRIMARY 8 buxback_site.bb_cat_business.cat_id 1 Using where 

When using only one match, the query uses a fulltext index I have on bb_business. When I have multiple matches, it does not seem to use any index.

Here are the indexes on bb_business:

PRIMARY  PRIMARY 2877       id  
store_id  UNIQUE 2877       store_id  
index_business_name  INDEX 2877       business_name  
business_name  FULLTEXT 1       business_name  
city  FULLTEXT 1       city  
state  
zip  

Here are the indexes on bb_categories:

PRIMARY  PRIMARY 15       id  
category_name  UNIQUE None       category_name  
category_name_2  FULLTEXT None       category_name 

I'm desparate!

Thank!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

濫情▎り 2024-09-22 02:16:40

问题是您强制 MySQL 创建临时表来解决查询。只要你进行多场比赛,这几乎就会成为一个问题。

如果您的用例确实需要您这样做,那么您有两个主要选择(我可以看到)。

  1. 创建一个非规范化的汇总表,您可以在其中需要匹配的所有列上放置全文索引。然后,保持此表更新(通过触发器、存储过程,或者只是在代码中执行查询时尽职调查)...然后针对该汇总表进行所有匹配(它应该消除对多个 MATCH 的需要)一个查询中的 子句)...
  2. 另一种选择是使用专用搜索引擎,例如 Apache SOLRSphinx。您需要单独搜索,然后从数据库中拉回结果,但是这些搜索引擎比 MySQL 强大得多(好吧,不强大,但更容易执行复杂查询),并且执行这些查询的速度比 MySQL 快得多。他们可以这样做,因为他们预先索引了一切(他们牺牲了磁盘空间 - 有时是很多 - 为了速度)......

The problem is that you're forcing MySQL to create temporary tables to resolve the query. That's pretty much going to be an issue so long as you're doing multiple matches.

If you're use case really requires you to do that, you have two main options (that I can see).

  1. Create a summary table which is de-normalized where you can put a full-text index on all the columns that you need to match against. Then, keep this table updated (either through triggers, stored procedures, or just diligence when you are executing your queries in code)... Then do all matching against that summary table (it should eliminate the need for having multiple MATCH clauses in one query)...
  2. The other option would be to use a dedicated search engine, like Apache SOLR or Sphinx. You would need to search separately and then pull the results back from the database, but those search engines are far more powerful than MySQL (Well, not powerful, but it's easier to do complex queries), and much faster than MySQL for executing those queries. They can do so because they pre-index everyting (they sacrifice disk space -sometimes a lot of it- for speed)...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文