[英]MySQL Match … Against query very slow
I work on a website running on Propel ORM and I have this query: 我在Propel ORM上运行的网站上工作,我有这个查询:
if(isset($args["QueryText"]) && $args["QueryText"] != "") {
$query = $query
->withColumn("(MATCH (Request.Subject, Request.Detail) AGAINST ('" . $args["QueryText"] . "' IN BOOLEAN MODE) + MATCH (Response.Response) AGAINST ('" . $args["QueryText"] . "' IN BOOLEAN MODE))", "RequestRelevance")
->condition('cond1', "(MATCH (Request.Subject, Request.Detail) AGAINST ('" . $args["QueryText"] . "' IN BOOLEAN MODE) + MATCH (Response.Response) AGAINST ('" . $args["QueryText"] . "' IN BOOLEAN MODE)) > 0.2")
->condition('cond2', 'Request.Id = ?', $args["QueryText"])
->where(array('cond1', 'cond2'), 'or')
->orderBy("RequestRelevance", Criteria::DESC);
}
which translates to the following in SQL: 在SQL中转换为以下内容:
SELECT DISTINCT
(MATCH (requests.subject, requests.detail) AGAINST ('46104' IN BOOLEAN MODE) +
MATCH (Response.response) AGAINST ('46104' IN BOOLEAN MODE))
AS RequestRelevance, requests.requestID AS "Id", requests.subject AS "Subject", requests.detail AS "Detail", requests.created AS "CreatedDate", requests.lastresponsedate AS "LastResponseDate", SupportStatus.supportstatusID AS "SupportStatus.Id", SupportStatus.supportstatus AS "SupportStatus.Name", SupportStatus.isnew AS "SupportStatus.IsNew", SupportStatus.isclosed AS "SupportStatus.IsClosed", CustomerGroup.customergroupID AS "CustomerGroup.Id", CustomerGroup.customergroup AS "CustomerGroup.Name", Site.siteID AS "Site.Id", Site.site AS "Site.Name", InternalUser.userID AS "InternalUser.Id", InternalUser.username AS "InternalUser.Username", User.userID AS "User.Id", User.username AS "User.Username", Customer.customerID AS "Customer.Id", Customer.customer AS "Customer.Name", Customer.customergroupID AS "Customer.CustomerGroupId", Customer.rate AS "Customer.Rate"
FROM requests
LEFT JOIN responses Response ON (requests.requestID=Response.requestID)
INNER JOIN supportstatus SupportStatus ON (requests.supportstatusID=SupportStatus.supportstatusID)
INNER JOIN customergroups CustomerGroup ON (requests.customergroupID=CustomerGroup.customergroupID)
INNER JOIN customers Customer ON (requests.customerID=Customer.customerID)
INNER JOIN sites Site ON (requests.siteID=Site.siteID)
LEFT JOIN users InternalUser ON (requests.internaluserID=InternalUser.userID)
LEFT JOIN users User ON (requests.userID=User.userID)
WHERE ((MATCH (requests.subject, requests.detail) AGAINST ('46104' IN BOOLEAN MODE) +
MATCH (Response.response) AGAINST ('46104' IN BOOLEAN MODE)) > 0.2 OR requests.requestID = '46104')
ORDER BY requests.created ASC,RequestRelevance DESC
It takes a good 20 second to load on the website using Propel and 7.020 seconds when running the SQL query. 使用Propel在网站上加载需要20秒,在运行SQL查询时需要7.020秒。
I tried the following one instead: 我尝试了以下一个:
SELECT DISTINCT
requests.requestID AS "Id", requests.subject AS "Subject", requests.detail AS "Detail", requests.created AS "CreatedDate", requests.lastresponsedate AS "LastResponseDate", SupportStatus.supportstatusID AS "SupportStatus.Id", SupportStatus.supportstatus AS "SupportStatus.Name", SupportStatus.isnew AS "SupportStatus.IsNew", SupportStatus.isclosed AS "SupportStatus.IsClosed", CustomerGroup.customergroupID AS "CustomerGroup.Id", CustomerGroup.customergroup AS "CustomerGroup.Name", Site.siteID AS "Site.Id", Site.site AS "Site.Name", InternalUser.userID AS "InternalUser.Id", InternalUser.username AS "InternalUser.Username", User.userID AS "User.Id", User.username AS "User.Username", Customer.customerID AS "Customer.Id", Customer.customer AS "Customer.Name", Customer.customergroupID AS "Customer.CustomerGroupId", Customer.rate AS "Customer.Rate"
FROM requests
LEFT JOIN responses Response ON (requests.requestID=Response.requestID)
INNER JOIN supportstatus SupportStatus ON (requests.supportstatusID=SupportStatus.supportstatusID)
INNER JOIN customergroups CustomerGroup ON (requests.customergroupID=CustomerGroup.customergroupID)
INNER JOIN customers Customer ON (requests.customerID=Customer.customerID)
INNER JOIN sites Site ON (requests.siteID=Site.siteID)
LEFT JOIN users InternalUser ON (requests.internaluserID=InternalUser.userID)
LEFT JOIN users User ON (requests.userID=User.userID)
WHERE (requests.subject LIKE '%46104%' OR requests.detail LIKE '%46104%' OR Response.response LIKE '%46104%' OR requests.requestID = '46104')
ORDER BY requests.created
which takes 3.308 seconds to execute. 执行需要3.308秒。 Removing
OR Response.response LIKE '%46104%'
from it reduces the time to 0.140 seconds. 删除
OR Response.response LIKE '%46104%'
会将时间减少到0.140秒。 The responses table contains 288317 rows and the responses.responses column is a TEXT() column with a FULLTEXT index. 响应表包含288317行,respond.responses列是带有FULLTEXT索引的TEXT()列。
What would be the best way to reduce the execution time of this search? 什么是减少此搜索执行时间的最佳方法? I have tried using this https://dba.stackexchange.com/questions/15214/why-is-like-more-than-4x-faster-than-match-against-on-a-fulltext-index-in-mysq answer however when I execute:
我尝试过使用这个https://dba.stackexchange.com/questions/15214/why-is-like-more-than-4x-faster-than-match-against-on-a-fulltext-index-in-mysq但是当我执行时回答:
SELECT responseID FROM
(
SELECT * FROM responses
WHERE requestID = 15000
AND responseID != 84056
) A
WHERE MATCH(response) AGAINST('twisted');
I get this error: 我收到此错误:
Error Code: 1191. Can't find FULLTEXT index matching the column list
Help will be greatly appreciated! 非常感谢帮助!
EDIT 1: 编辑1:
Tried @Richard EB's query: 试过@Richard EB的查询:
ALTER TABLE responses ADD FULLTEXT(response)
288317 row(s) affected Records: 288317 Duplicates: 0 Warnings: 0 78.967 sec
However: 然而:
SELECT responseID FROM ( SELECT * FROM responses WHERE requestID = 15000 AND responseID != 84056 ) A WHERE MATCH(response) AGAINST('twisted') LIMIT 0, 2000
Error Code: 1191. Can't find FULLTEXT index matching the column list 0.000 sec
Removing DISTINCT
reduces the execution time to 0.952 seconds however it doesn't retrieve the results I need. 删除
DISTINCT
会将执行时间减少到0.952秒,但它不会检索我需要的结果。
EDIT 2: 编辑2:
Executing this query: 执行此查询:
SELECT DISTINCT
responses.requestID AS "Id" FROM responses WHERE MATCH(response) AGAINST('twisted')
takes 0.062 secs. 需要0.062秒。
Executing this: 执行此:
SELECT DISTINCT responses.requestID
FROM responses
WHERE (
MATCH (Responses.response) AGAINST ('twisted' IN BOOLEAN MODE)
)
ORDER BY responses.requestID ASC
only takes 0.046 secs. 只需0.046秒。 However, selecting from Requests and joining Responses is what slows down the query.
但是,从请求中选择并加入响应会降低查询速度。 I'm not sure if it means that the whole query has to be completely rewritten to select from Responses and joining Requests instead?
我不确定这是否意味着必须完全重写整个查询以从响应和加入请求中进行选择?
EDIT 3: 编辑3:
Here are the indexes that I have on Requests
and Responses
tables: 以下是我在
Requests
和Responses
表中的索引:
# Table, Non_unique, Key_name, Seq_in_index, Column_name, Collation, Cardinality, Sub_part, Packed, Null, Index_type, Comment, Index_comment
responses, 0, PRIMARY, 1, responseID, A, 288317, , , , BTREE, ,
responses, 1, requestID, 1, requestID, A, 48052, , , YES, BTREE, ,
responses, 1, response, 1, response, , 1, , , YES, FULLTEXT, ,
responses, 1, response_2, 1, response, , 1, , , YES, FULLTEXT, ,
responses, 1, response_3, 1, response, , 1, , , YES, FULLTEXT, ,
# Table, Non_unique, Key_name, Seq_in_index, Column_name, Collation, Cardinality, Sub_part, Packed, Null, Index_type, Comment, Index_comment
requests, 0, PRIMARY, 1, requestID, A, 46205, , , , BTREE, ,
requests, 1, supportstatusID, 1, supportstatusID, A, 14, , , YES, BTREE, ,
requests, 1, internaluserID, 1, internaluserID, A, 344, , , YES, BTREE, ,
requests, 1, customergroupID, 1, customergroupID, A, 198, , , , BTREE, ,
requests, 1, userID, 1, userID, A, 1848, , , YES, BTREE, ,
requests, 1, siteID, 1, siteID, A, 381, , , YES, BTREE, ,
requests, 1, request, 1, subject, , 1, , , YES, FULLTEXT, ,
requests, 1, request, 2, detail, , 1, , , YES, FULLTEXT, ,
requests, 1, request, 3, ponumber, , 1, , , YES, FULLTEXT, ,
A LIKE search will go through every record and perform non-exact string comparison, which is why it's so slow. LIKE搜索将遍历每条记录并执行非精确的字符串比较,这就是它如此慢的原因。
The mysql error you've pasted indicates that the column referenced in the MATCH clause doesn't have a fulltext index (or it does, but it's not as it's referenced in the MATCH clause). 您粘贴的mysql错误表明MATCH子句中引用的列没有全文索引(或者它有,但它不是在MATCH子句中引用的)。
Assuming you're using MyISAM or have MySQL 5.6 and InnoDB, try: 假设您正在使用MyISAM或拥有MySQL 5.6和InnoDB,请尝试:
ALTER TABLE responses ADD FULLTEXT(response);
Edit: Answer (in comments): "If there are two columns mentioned in the MATCH statement, then there should be one fulltext index on both of those columns, not two fulltext indexes on each column" 编辑:答案(在评论中):“如果MATCH语句中提到了两列,那么这两列上应该有一个全文索引,而不是每列上有两个全文索引”
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.