加快sql查询到mysql?

时间:2010-03-21 03:50:02

标签: php mysql database caching

在我的mysql数据库中,我有一个地理名称数据库,包含所有国家,州和城市。

我正在使用它创建一个级联菜单,以便用户可以选择他来自哪里:country - >国家 - >县 - >城市。

但主要问题是,每当我想获取子行列表时,查询将搜索该表中的所有7百万行,这需要花费10-15秒。

我想知道如何加快速度:缓存?表格视图?以某种方式重组表结构?

最重要的是,我该如何做这些事情?有没有可以链接到我的好教程?

我感谢所有帮助和反馈,讨论处理这个问题的聪明方法!

更新:这是我的表结构:

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查询:

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

我应该只为2列创建索引:parent_id和feature_class?

一个问题:使用solr而不是使用mysql创建索引不是更好吗?一个好处是我已经使用solr而另一个是它支持全文搜索。所以也许它更好所以我不使用solr和mysql(2件事要擅长)?

5 个答案:

答案 0 :(得分:1)

如上所述,更多信息会有所帮助(Sql,数据库结构)。

AJAX建议很好,但你也可以在没有ajax的情况下做到这一点。

不要在选择所有数据的任何点执行选择。这将非常缓慢。

首先,填充唯一的国家/地区列表。允许用户从此列表中进行选择。用户通过AJAX选择国家/地区或刷新整个页面后,只填写该国家/地区的状态列表 - 例如(从国家= @country的地理位置选择州)。当用户选择一个州时,填写该国家和州的县列表 - 例如(从国家= @country和州= @state的地理选择国家/地区)。继续以这种方式为这个城市。

我对MySql不是很熟悉,但在SqlServer中我会在(Country,State,County,City)上创建一个索引来加速这组查询。我不确定MySql是否能用这个索引加速整个查询集。

当然,我对这里的数据结构做了一些假设,所以这些信息可能相关也可能不相关。

答案 1 :(得分:0)

发布您的SQL以获得更好的回复,但一般情况下:

  • 在您加入/加入的字段上制作索引。
  • 请勿使用“SELECT *” - 仅选择您需要的字段。
  • 水合物作为数组而不是物体。

此外,如果菜单永远不会更改,请将HTML缓存在文件中。您甚至可以只缓存国家/州HTML,然后通过AJAX获取城市,如果它们经常更改。

答案 2 :(得分:0)

我相信像这样的东西通常是用AJAX完成的。在开始时,您只加载国家/地区名称,选择一个国家/地区名称后,您将动态加载该国家/地区的州名称,然后在此之后重复每个细分。

答案 3 :(得分:0)

这是分区表甚至具有子分区的好方案。您可以按国家/地区对表进行分区,然后按州进行子分区。这将显着减少您的查询必须搜索的数据量,因为可以从执行计划中删除大量数据。

Here是开始获取有关MySQL分区的信息的好地方。

除了分区(即使您选择不进行分区),您还需要在搜索的列上创建索引,因为这样可以进一步提高查询的性能。

Here是关于如何创建索引的MySQL文档,但实际上制作索引的难点在于知道要索引的内容。通常,您将定位查询中WHERE子句中显示的列或您加入的列上的列。这是非常通用的,你没有(在很多情况下不应该)索引where子句中的每一列,但这是一个很好的起点。根据问题中给出的有限数据,您很可能需要国家和地区的综合指数,以加快城市的选择。您将需要使用解释计划来确定何时需要索引以及查询是否实际使用它。在SO上搜索“MySQL索引”,你会找到关于索引表的时间,地点和方法的足够信息。

如果您还没有,它将有助于规范化您的数据。例如,如果您的表目前看起来像:

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

应该改为:

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

从UI的角度来看,您需要以只填充必要数据然后使用匹配条件生成其他数据输入点的方式编写它。因此,在初始加载时,您将使用:

填充国家/地区输入
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;

等等,直到您检索用户数据为止。

希望这有帮助。

答案 4 :(得分:0)

ALTER TABLE geonames_copy ADD INDEX (parent_id, feature_class);

应该做的伎俩。只有parent_id的索引也可能正常工作。