2013-02-01 3 views
1

ColdFusion 웹 사이트에서 호출되는 ColdFusion Component에서 다음 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의의 필요한 것 : 초기 문자가 고정되지 않기 때문에

(((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

OK ...단어의 시작 부분에서 와일드 카드를 사용하면 0.5 초를 절약 할 수 있지만 그렇게해야한다는 것은 싫어합니다. – SiriusPhil

+0

예, place_cats (placeId, catId)에 대한 색인이 있습니다. – SiriusPhil

+0

그래, 좋아하는 것 대신 전체 텍스트 검색을 할 가치는 없을까? –