我有一个html搜索表单,如下图所示:
在此搜索表单中,我需要搜索7个表格中的数据。在这7个表中,存储了超过11K的数据。因此我使用以下sql JOIN
查询来获取结果。
但是如果例如,它需要花费很长时间来获得结果(有时显示错误信息)我搜索姓氏= s 。我的意思是如果表列中有大量数据。怎么能解决这个问题?我使用LIMIT
,但我认为它在此查询中没有帮助,因为首先我必须搜索所有7个表格!
Sql Query:
$getSearch .= " cd.cdid, cd.family_name, cd.given_name, cd.department, cd.title, company.cid, company.company_name, users.nickname, contact_label.label_data FROM
contact_details as cd
LEFT JOIN users ON users.user_id = cd.user_id
LEFT JOIN company ON company.cid = cd.cid
LEFT JOIN contact_docs ON contact_docs.cdid = cd.cdid
LEFT JOIN userkeywords ON userkeywords . cdid = cd . cdid
LEFT JOIN keywords ON keywords . kid = userkeywords . kid
LEFT JOIN contact_label ON contact_label.cdid = cd.cdid
WHERE 1=1 ";
if(!empty($ad_company)){
$getSearch .= "AND company.company_name LIKE '$ad_company%' ";
}
if(!empty($ad_fname)){
$getSearch .= "AND cd.family_name LIKE '$ad_fname%' ";
}
if(!empty($ad_department)){
$getSearch .= "AND cd.department LIKE '$ad_department%' ";
}
if(!empty($ad_mp)){
$getSearch .= "AND cd.mp >= '$ad_mp' ";
}
if(!empty($ad_e2)){
$getSearch .= "AND cd.e2 >= '$ad_e2' ";
}
if(!empty($ad_pl)){
$getSearch .= "AND cd.pl >= '$ad_pl' ";
}
if(!empty($ad_ap)){
$getSearch .= "AND cd.ap >= '$ad_ap' ";
}
if(!empty($ad_j2)){
$getSearch .= "AND cd.j2 >= '$ad_j2' ";
}
if(!empty($ad_agreater)){
$getSearch .= "AND cd.age >= '$ad_agreater' ";
}
if(!empty($ad_aless)){
$getSearch .= "AND cd.age <= '$ad_aless' ";
}
if(!empty($ad_agreater) && !empty($ad_aless)){
$getSearch .= "AND cd.age BETWEEN '$ad_agreater' AND '$ad_aless'";
}
if(!empty($ad_sgreater)){
$getSearch .= "AND cd.comp >= '$ad_sgreater' ";
}
if(!empty($ad_sless)){
$getSearch .= "AND cd.comp <= '$ad_sless' ";
}
if(!empty($ad_sgreater) && !empty($ad_sless)){
$getSearch .= "AND cd.comp BETWEEN '$ad_sgreater' AND '$ad_sless'";
}
if(!empty($ad_noteterm)){
$ad_noteterm = preg_replace("/\{ASUSIBBIR\}(.+?)\s:\s(.+?)\{ASUSIBBIR\}/m", "$2", $ad_noteterm);
$getSearch .= "AND LOCATE('$ad_noteterm', REPLACE (notesUpdate, '{ASUSIBBIR}', ' '))";
}
if(!empty($ad_cnote)){
$getSearch .= "AND LOCATE('$ad_cnote', cd.characterNotes)";
}
if(!empty($ad_twork)){
$getSearch .= "AND contact_label.label_data LIKE '%$ad_twork%'";
}
if(!empty($ad_tmobile)){
$getSearch .= "AND cd.mobile_phone like '%$ad_tmobile%'";
}
if(!empty($ad_resume)){
$getSearch .= "AND LOCATE('$ad_resume', contact_docs.file_content)"; //is this the resume? yes
}
if(!empty($ad_datefrom) && empty($ad_dateto)){
$getSearch .= "AND cd.created_date BETWEEN '$ad_datefrom'AND '$date'";
}
if(!empty($ad_dateto) && empty($ad_datefrom)){
$getSearch .= "AND cd.created_date BETWEEN date('0000-00-00') AND '$ad_dateto' ";
}
if(!empty($ad_datefrom) && !empty($ad_dateto)){
$getSearch .= "AND cd.created_date BETWEEN '$ad_datefrom' AND '$ad_dateto'";
}
if(!empty($ad_type)){
$getSearch .= "AND cd.type = '$ad_type' ";
}
if(!empty($ad_wemail)){
$getSearch .= "AND cd.email LIKE '$ad_wemail%'";
}
if(!empty($ad_pemail)){
$getSearch .= "AND cd.email_private LIKE '$ad_pemail%'";
}
if(!empty($ad_title)){
$getSearch .= "AND cd.title LIKE '$ad_title%'";
}
if(!empty($ad_source)){
$getSearch .= "AND cd.source LIKE '$ad_source%'";
}
if(!empty($ad_consultant)){
$getSearch .= "AND users.nickname LIKE '%$ad_consultant%'";
}
if(!empty($ad_keyword)){
$ad_keyword_param = str_replace(",","','",$ad_keyword);
$getSearch .= " AND keywords.keywordName IN ('$ad_keyword_param') ";
}
$getSearch .= " GROUP BY cd.user_id, cd.cid, cd.cdid ";
if(!empty($ad_keyword)){
$ad_keyword_param = str_replace(",",",",$ad_keyword);
$getSearch .= " ) as a WHERE keywordName LIKE '$ad_keyword_param%' ";
}
$f = microtime(true);
//$getSearch .= "ORDER BY cd.given_name ASC";
$getSearch .= "ORDER BY cd.given_name DESC LIMIT 10";
$getSearch = mysqli_query($link, $getSearch);
答案 0 :(得分:0)
你需要做的第一件事就是规范你的数据库,MySQL对连接提供了很好的支持,但正如你所经历的那样,当使用三个以上的连接时它有几个回退,因此重新设计你的数据库是我的第一个建议
其他替代方法是使用存储过程或视图,这应该更快。
答案 1 :(得分:0)
希望所有联接都是必要的,这是一个巨大的查询,这需要很长时间和正常。希望你有所有需要的索引。
首先检查索引未命中。 在存储过程中尝试,因为在动态查询运行中,每次调用查询语句时,服务器端的DB驱动程序都必须进行解析,分析,计划和优化。将过程存储在服务器上要高效得多,数据库引擎可以预先编译和分析过程一次,然后将其提交到缓存并直接运行。
即使以上都不起作用,也有两种选择。
<强> 1。增加PHP时间限制
编辑php.ini
;;;;;;;;;;;;;;;;;;;
; Resource Limits ;
;;;;;;;;;;;;;;;;;;;
; Maximum execution time of each script, in seconds
; http://php.net/max-execution-time
; Note: This directive is hardcoded to 0 for the CLI SAPI
max_execution_time = 500
或方法调用
ini_set('max_execution_time', 500);
<强> 2。重新设计查询
通过所有这些连接,显而易见的是查询速度很慢。您需要对表格进行反规范化(如果您对冗余数据没问题),或者您必须考虑在第一页中是否需要所有这些信息。
Ex:cd.cdid,cd.family_name,cd.given_name,cd.department,cd.title,company.cid可以显示在列表页面中,您可以在用户悬停/点击结果时显示其他详细信息(懒加载羽毛信息)
但是,当您搜索所有列时,可能无法实现。
答案 2 :(得分:0)
您必须为每个查询创建索引。 如果您搜索“名字”,该脚本会进行这样的查询。
select cd.cdid, cd.family_name, cd.given_name, cd.department, cd.title, company.cid, company.company_name, users.nickname, contact_label.label_data FROM
contact_details as cd
LEFT JOIN users ON users.user_id = cd.user_id
LEFT JOIN company ON company.cid = cd.cid
LEFT JOIN contact_docs ON contact_docs.cdid = cd.cdid
LEFT JOIN userkeywords ON userkeywords . cdid = cd . cdid
LEFT JOIN keywords ON keywords . kid = userkeywords . kid
LEFT JOIN contact_label ON contact_label.cdid = cd.cdid
WHERE 1=1 AND cd.family_name LIKE 'SEARCH_WORD%'
Mysql必须有索引。
users table : indexed column = user_id (Maybe PK?)
company table : indexed column = cid (Maybe PK?)
contact_docs table : indexed column = cdid (Maybe PK?)
userkeywords table : indexed column = cdid (Maybe PK?)
keywords table : indexed column = kid (Maybe PK?)
contact_label table : indexed column = cdid (Maybe PK?)
contact_details table : indexed column = family_name, cid(Maybe PK?), cdid
并且,您必须通过EXPLAIN验证SQL使用。