[英]speed up a sql query to mysql?
在我的mysql数据库中,我有一个地名数据库,其中包含所有国家,州和城市。
我正在使用它来创建级联菜单,以便用户可以选择他所在的位置:国家->州->县->城市。
但是主要的问题是,每次我想要获取子行列表时,查询将搜索该表中的所有700万行,这需要花费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件事要擅长)?
如前所述,更多信息会有所帮助(Sql,数据库结构)。
AJAX建议是一个很好的建议,尽管您也可以不用ajax来做到这一点。
在选择所有数据的任何时候都不要执行选择。 这将非常慢。
首先,填充唯一的国家/地区列表。 允许用户从该列表中进行选择。 用户通过AJAX或刷新整个页面选择国家/地区后,仅填充该国家/地区的州列表-之类的(从地名中选择国家(国家= @country))。 当用户选择一个州时,填充该国家和州的县列表-类似于(从地名中选择国家,其中country = @country和state = @state)。 以这种方式继续前往城市。
我对MySql不太熟悉,但是在SqlServer中,我将在(国家,州,县,市)上创建索引以加快这组查询的速度。 我不确定MySql是否可以使用此索引来加速整个查询集。
当然,我在这里对您的数据的结构进行一些假设,因此此信息可能相关,也可能无关。
发布您的SQL以获得更好的答复,但是通常:
另外,如果菜单从未更改,则将HTML缓存在文件中。 您甚至可以只缓存国家/地区HTML,然后如果它们经常更改,则通过AJAX提取城市。
我相信这样的事情通常是用AJAX完成的。 刚开始时,您仅加载国家/地区名称,选择一个国家/地区名称后,您将动态加载该国家/地区的州名称,然后在此之后对每个细分重复此操作。
这是对表进行分区甚至具有子分区的好方案。 您可以按国家对表进行分区,然后按州进行子分区。 由于可以从执行计划中删除大量数据,因此这将大大减少查询必须搜索的数据量。
这是开始获取有关MySQL分区信息的好地方。
除了分区(即使您选择不分区)之外,您还需要在搜索的列上创建索引,因为这将进一步提高查询的性能。
这是有关如何创建索引的MySQL文档,但实际上制作索引的难点在于知道要建立索引的内容。 通常,您将定位查询中WHERE子句中显示的列或JOIN所在的列。 这很普遍,您不必(在许多情况下也不必)在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;
依此类推,直到您检索用户数据。
希望这可以帮助。
ALTER TABLE geonames_copy ADD INDEX (parent_id, feature_class);
应该可以。 仅在parent_id上的索引也可能会正常工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.