2010-03-21 3 views
2

나는 모든 국가, 주 및 도시를 포함하는 geonames 데이터베이스 있어요.mysql에 대한 SQL 쿼리 속도 향상 내 mysql 데이터베이스에

사용자가 국가 -> 주 -> 군 -> 도시를 선택할 수 있도록 계단식 메뉴를 만드는 데이 방법을 사용하고 있습니다.

하지만 주요 문제는 어린이 행 목록을 가져올 때마다 해당 테이블의 7 백만 행을 모두 검색하여 10-15 초가 걸리는 것입니다.

나는 이것을 어떻게 할 수 있었는지 궁금하다 : 캐싱? 테이블보기? 어떻게 든 테이블 구조를 재구성?

가장 중요한 것은 어떻게해야합니까? 거기에 나와있는 좋은 자습서가 있습니까?

이 문제를 현명하게 처리하는 방법에 대한 도움과 의견을 보내 주시면 감사하겠습니다.

UPDATE : 여기 내 테이블 구조입니다 :

CREATE TABLE `geonames_copy` (
    `geoname_id` mediumint(9) NOT NULL, 
    `parent_id` mediumint(9) DEFAULT NULL, 
    `name` varchar(200) DEFAULT NULL, 
    `ascii_name` varchar(200) DEFAULT NULL, 
    `alternate_names` varchar(4000) DEFAULT NULL, 
    `latitude` decimal(10,7) DEFAULT NULL, 
    `longitude` decimal(10,7) DEFAULT NULL, 
    `feature_class` char(1) DEFAULT NULL, 
    `feature_code` varchar(10) DEFAULT NULL, 
    `country_code` varchar(2) DEFAULT NULL, 
    `cc2` varchar(60) DEFAULT NULL, 
    `admin1_code` varchar(20) DEFAULT NULL, 
    `admin2_code` varchar(80) DEFAULT NULL, 
    `admin3_code` varchar(20) DEFAULT NULL, 
    `admin4_code` varchar(20) DEFAULT NULL, 
    `population` bigint(20) DEFAULT NULL, 
    `elevation` int(11) DEFAULT NULL, 
    `gtopo30` smallint(6) DEFAULT NULL, 
    `time_zone` varchar(40) DEFAULT NULL, 
    `modification_date` date DEFAULT NULL, 
    PRIMARY KEY (`geoname_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8; 

가 여기에 SQL 쿼리는 다음과 같습니다 PARENT_ID 및 feature_class :

  $query = "SELECT geoname_id, name 
        FROM geonames 
        WHERE parent_id = '$geoname_id' 
        AND (feature_class = 'A')"; 

난 그냥 2 열에 대한 인덱스를 생성해야합니까?

한 가지 질문 : mysql 대신 solr을 사용하여 색인을 만드는 것이 더 좋지 않습니까? 한 가지 이점은 이미 sol을 사용하고 있으며 다른 장점은 전체 텍스트 검색을 지원한다는 것입니다. 그래서 어쩌면 내가 solr과 mysql (2 가지 좋은 일)을 사용하지 않는 것이 더 낫다.

+0

현재 테이블 구조는 어떻게 생겼습니까?필요할 때 인덱스를 사용하고 있습니까? 적절한 인덱스를 사용하면 이와 같은 쿼리가 거의 즉시 발생합니다. – Wolph

+0

각 항목은 동일한 테이블의 다른 항목을 참조합니다. 그게 내가 케딩 메뉴를 만드는 방법이야. 어떻게 인덱스를 만들 수 있으며 어떻게 작동합니까? 좀 더 많은 정보 (자습서 링크)를 보내 주시겠습니까? 감사합니다 –

+0

인덱스는 확실히 귀하의 질문에 대한 답변입니다 - 귀하의 현재 테이블 구조를 게시하고 우리는 당신이 인덱스를 만들 수 있습니다. –

답변

1

언급 한대로 더 많은 정보가 도움이 될 것입니다 (SQL, 데이터베이스 구조).

AJAX 제안은 좋은 것입니다. 아약스 없이도이 작업을 수행 할 수 있습니다.

모든 데이터를 선택하는 지점에서 선택을 실행하지 마십시오. 이것은 매우 느릴 것입니다.

먼저 국가 목록 만 채 웁니다. 사용자가이 목록에서 선택하도록 허용합니다. 사용자가 AJAX를 통해 국가를 선택하거나 전체 페이지를 새로 고친 다음 해당 국가의 상태 목록 만 채우십시오 (예 : geonames from country = @country). 사용자가 주를 선택하면 해당 국가 및 주에 대한 카운티 목록을 채 웁니다 (예 : country = @country 및 state = @state와 같은 geonames에서 국가 선택). 이 방법으로 도시를 계속하십시오.

저는 MySql에 익숙하지 않지만 SqlServer에서는이 쿼리 집합의 속도를 높이기 위해 (국가, 주, 군,시)에 대한 인덱스를 만들 것입니다. MySql이이 인덱스로 전체 쿼리 집합을 가속화 할 수 있는지 여부는 확실하지 않습니다.

물론 데이터가 여기에 어떻게 구성되어 있는지에 대해 몇 가지 가정을하고 있습니다. 따라서이 정보는 관련성이 있거나 그렇지 않을 수 있습니다.

+0

테이블 구조를 살펴보면 (parent_id, feature_class)에 대한 색인이 트릭을 수행해야합니다. MySql에서 수행 할 수있는 방법이있는 경우 쿼리 실행 계획을보고 인덱스가 사용되고 있는지 확인할 수 있습니다. 트레이드 오프가 포함되어 있지만 인덱스의 끝까지 찾는 필드를 지정하는 경우 (모든 정보가 검색 될 수있을 때 더 빠른 쿼리가 발생할 수 있음을 알게되었습니다) 조회가없는 색인에서 직접 테이블로. 테스트하고 어떤 것이 가장 적합한 지 결정하십시오. – Krazzy

0

포스트 당신의 더 나은 응답을위한 SQL하지만, 일반적으로 :

  • 당신이 조인/알의에 할 필드에 인덱스를 확인합니다.
  • "SELECT *"를 사용하지 마십시오. 필요한 필드 만 선택하십시오.
  • 개체 대신 배열로 수화.

또한 메뉴가 변경되지 않으면 HTML을 파일에 저장하십시오. 국가/주 HTML 만 캐시 한 다음 자주 변경하는 경우 AJAX를 통해 도시를 가져올 수도 있습니다.

+0

네, 그건 html에있는 국가 -> 주를 가지고 현명했습니다. 그러나 도시들은 여전히 ​​가져올 시간이 오래 걸릴 것입니다. 이 속도를 높이는 방법이 있습니까? 색인에 대해 무엇입니까? 너 그것에 대해 좀 더 말해 줄 수있어? –

+0

MySQL 매뉴얼은 당신의 친구입니다. 그래서 우리는 장님을 쏘지 않기 위해 코드/SQL을 게시하고 있습니다. –

+0

plz 내 업데이트를 읽었습니다. ive는 SQL 구조를 게시했습니다. –

0

저는 AJAX로 이런 일을 처리한다고 생각합니다. 처음에는 국가 이름 만로드하고 하나를 선택하면 해당 국가의 상태 이름을 동적으로로드 한 다음 그 후에 각 하위 섹션에 대해 반복합니다.

+0

예, 그것이 내가 의도 한 방법입니다. 하지만 주요 문제는 각 SELECT 쿼리가 그 테이블에서 7 백만 행을 거쳐야하기 때문에 오랜 시간이 걸릴 것이라는 점입니다. 어떻게 속도를 낼 수 있을지 궁금해. –

0

테이블을 분할하고 하위 파티션을 갖는 경우에도 좋은 시나리오입니다. 국가별로 테이블을 분할 한 다음 상태별로 하위 파티셔닝 할 수 있습니다. 이렇게하면 거대한 데이터 세그먼트가 실행 계획에서 제거 될 수 있으므로 쿼리에서 검색해야하는 데이터 양이 크게 줄어 듭니다.

Here은 MySQL 파티셔닝에 대한 정보를 얻기에 좋은 곳입니다.

파티셔닝과 함께 (그리고 파티셔닝을하지 않더라도) 검색 할 컬럼에 인덱스를 만들어 쿼리 성능을 향상시킬 수 있습니다.

Here은 인덱스를 만드는 방법에 대한 MySQL 설명서이지만 실제로 인덱스를 만드는 것에 대한 어려운 부분은 무엇을 색인 할 것인지를 아는 것입니다. 일반적으로 쿼리의 WHERE 절이나 JOIN 할 열에 표시되는 열을 대상으로 지정합니다. 이것은 꽤 일반적이며 where 절에있는 모든 열을 인덱싱해야하지는 않습니다 (많은 경우에 있어서는 안됩니다). 그러나 시작하기에 좋은 곳입니다. 이 질문에 제공된 제한된 데이터를 기반으로, 도시 선택의 속도를 높이기 위해 국가 및 지역에 복합 지수가 가장 필요할 것입니다. 인덱스가 필요한시기와 실제로 쿼리에서 사용되는지 여부를 결정하기 위해 Explain 계획을 사용하려고합니다. SO에서 "MySQL 인덱싱"을 검색하면 인덱싱 테이블의 언제, 어디서, 어디서나 정보를 찾을 수 있습니다.

데이터를 정상화하는 데 도움이됩니다.

usa;fl;miami;.... 
usa;fl;orlando;.... 

그것은 같은 것을 변경해야합니다 : 예를 들어, 테이블은 현재 뭔가처럼 보이는 UI의 관점에서

COUNTRY Table: 
-------------- 
COUNTRY_KEY   1 
THREE_LETTER   'usa' 
COUNTRY_NAME   'united states' 
..OTHER COLUMNS.... 

REGION Table: 
-------------- 
COUNTRY_KEY   1 
REGION_KEY    10 
REGION_CODE   'fl' 
REGION_NAME   'florida' 
..OTHER COLUMNS.... 

CITY Table: 
-------------- 
REGION_KEY    10 
CITY_KEY    20 
CITY_NAME    'miami' 
LAT     123.12 
LONG     123.12 
..OTHER COLUMNS---- 

, 당신은 방법을 쓰고 싶을 것이다 여기서 필요한 데이터 만 채우고 일치하는 기준으로 다른 데이터 진입 점을 생성합니다. 사용자들이 관심있는 국가를 선택하면 다음 그 나라 키로 모든 지역을 선택

SELECT country_key, three_letter 
FROM COUNTRY 
ORDER BY three_letter; 

: 그래서 초기로드에, 당신은 함께 국가 입력을 채울 수 있습니다.

SELECT region_key, region_code 
FROM REGION WHERE country_key = :input_country_key 
ORDER BY region_code; 

이렇게 사용자 데이터를 검색 할 때까지.

희망이 도움이됩니다.

+0

제안 후에 내 데이터를 표준화 할 수없는 이유가 있습니다. 일부 항목은 기본 구조를 따르지 않습니다. 일부 엔트리 (도시)에는 자손 (지역, 교외 지역) 등이 있으므로 정적 구조를 따르지 않고 동적 인 구조를 따르게됩니다. 그래서 geonames는 하나의 테이블 만 가지고 있으며 각 항목은 parent_id에 의해 부모 항목에 연결됩니다. plz 내 업데이 트를 읽었습니다. ive는 SQL 구조를 게시했습니다. 나는 색인에 대해 살펴볼 것입니다 ... 해결책처럼 들립니다. –

0
ALTER TABLE geonames_copy ADD INDEX (parent_id, feature_class); 

트릭을해야합니다. parent_id에 대한 색인도 잘 작동합니다.

+0

당신의 SQL 문과 이것 사이의 차이점은 무엇입니까? CREATE INDEX index_name ON table_name (columnname1_columnname2) "; –

+0

나는 그것들이 동등한 구문이라고 생각합니다. (syntaxi? syntaxen?) CREATE INDEX는 인덱스에 이름을 부여해야합니다. isn 정말 필요해. –