2013-02-01 68 views
1

我从ColdFusion网站调用的Cold Fusion组件中有以下MYSQL查询。我有一个自定义采取,基本上为以下字段构建一个布尔查询:“PlaceName,Country,Adm1,adm2,adm3,locality”。如何加快复杂的MYSQL查询?

<!--- SEARCH PLACES 2---> 
<cffunction name="searchPlaces_full" access="public" returntype="query"> 
    <cfargument name="q" type="string" required="yes"> 


    <CF_BOOLSEARCH searchterm="#arguments.q#" field="PlaceName,Country,Adm1,adm2,adm3,locality " booloperator="and"> 
    <cfquery name="GetPlaces" datasource="#application.settings.dsn#"> 
    SELECT 
     places.CatID, 
     places.PlaceName, 
     places.PlaceID, 
     places.Address1, 
     places.PostalCode, 
     places.Locality, 
     places.Address2, 
     places.ImageThumb, 
     places.Adm1, 
     places.Country, 
     places.Adm2, 
     places.Adm3, 
     places.contributorid, 
     places.lng, 
     places.lat, 
     places.verified, 
     places.verified_by, 
     places.verified_date 
    FROM places INNER JOIN places_cats ON places.PlaceID = places_cats.PlaceID 
    WHERE 
    <cfif len(trim(arguments.q))> 
    (#PreserveSingleQuotes(boolsearch)#) 
    <cfelse> 
    1=0 
    </cfif> 
    AND places_cats.CATID IN (#arguments.categories#) 
    GROUP BY 
     places.CatID, 
     places.PlaceName, 
     places.PlaceID, 
     places.Address1, 
     places.PostalCode, 
     places.Locality, 
     places.Address2, 
     places.ImageThumb, 
     places.Adm1, 
     places.Country, 
     places.Adm2, 
     places.Adm3, 
     places.contributorid, 
     places.lng, 
     places.lat, 
     places.verified, 
     places.verified_by, 
     places.verified_date 
     ORDER BY PlaceName 
     </cfquery> 


    <cfreturn getPlaces> 
</cffunction> 

数据库中有624227条记录。如果我搜索Chappaqua,实际运行的SQL如下所示:

 SELECT 
     places.CatID, 
     places.PlaceName, 
     places.PlaceID, 
     places.Address1, 
     places.PostalCode, 
     places.Locality, 
     places.Address2, 
     places.ImageThumb, 
     places.Adm1, 
     places.Country, 
     places.Adm2, 
     places.Adm3, 
     places.contributorid, 
     places.lng, 
     places.lat, 
     places.verified, 
     places.verified_by, 
     places.verified_date 
    FROM places INNER JOIN places_cats ON places.PlaceID = places_cats.PlaceID 
    WHERE 

    (((PlaceName LIKE '%chappaqua%') OR (Country LIKE '%chappaqua%') OR (Adm1 LIKE '%chappaqua%') OR (adm2 LIKE '%chappaqua%') OR (adm3 LIKE '%chappaqua%') OR (locality LIKE '%chappaqua%'))) 

    AND places_cats.CATID IN (1,21,15,32,16,26,29,27,28,25,75,89,38,5,36,88,87,31,33,24,35,37,90,39,40,34,30,9,8,7,11,20,19,96,97,95,13,17,14,12,3,2,4,84,85,86) 
    GROUP BY 
     places.CatID, 
     places.PlaceName, 
     places.PlaceID, 
     places.Address1, 
     places.PostalCode, 
     places.Locality, 
     places.Address2, 
     places.ImageThumb, 
     places.Adm1, 
     places.Country, 
     places.Adm2, 
     places.Adm3, 
     places.contributorid, 
     places.lng, 
     places.lat, 
     places.verified, 
     places.verified_by, 
     places.verified_date 
     ORDER BY PlaceName 

我知道它很丑并且很复杂。大约需要1836ms运行。有没有更好的方法来编写查询或代码,以便在一秒之内加快返回的数据?

这里是解释上的SQL: SQL EXPLAIN

+4

向我们显示您的索引。告诉我们你的'EXPLAIN'。 – Kermit

+0

您似乎不使用聚合函数,那么GROUP BY是什么? – Strawberry

+2

@Strawberry他们正试图获得'DISTINCT'行 – Taryn

回答

4

的问题是,发动机是做表的全表扫描,然后排序为group by结果。

全表扫描看起来几乎是必要的,因为like S的:

(((PlaceName LIKE '%chappaqua%') OR (Country LIKE '%chappaqua%') OR (Adm1 LIKE '%chappaqua%') OR (adm2 LIKE '%chappaqua%') OR (adm3 LIKE '%chappaqua%') OR (locality LIKE '%chappaqua%'))) 

的问题是在地名索引不能使用,因为最初的字符不固定的。

所以。 。 。你能删除group by吗?您至少可以用distinct替换它,但我认为这不会影响查询计划。你有place_cats(placeId, catId)的索引吗?这至少会阻止查询读取类别表,以便它可以执行索引查找。

您是否可以将搜索仅限于字段开头的单词?

我能想到的唯一另一种选择是切换到在MySQL中使用全文索引。

+0

好的...从字的开头删除通配符确实节省了半秒,但我不愿意这样做。 – SiriusPhil

+0

是的,我在place_cats(placeId,catId)上有一个索引。 – SiriusPhil

+0

是啊,不是值得一看全文搜索来代替所有那些东西吗? –