重复时MySQL查询运行速度较慢

时间:2019-03-10 11:58:28

标签: mysql geolocation query-performance

以下查询(我没有写过)基于50,000条记录表中的距离计算进行搜索。我第一次运行它(在phpMyAdmin中),它在0.25秒内运行。如果我立即再次运行它,则需要30秒钟以上。我尝试添加SQL_NO_CACHE,但没有区别。由于在生产中同一查询可以短时间多次运行,所以这是一个主要问题。

请注意,如果用户在搜索页面上选择其他条件(关键字),而这些条件需要进行字符串搜索的联接表,那么问题就消除了;我假设首先进行文本搜索,而剩下的距离计算较少。 (这就是为什么主键上有GROUP BY的原因;这些扩展的搜索可以产生PK的多个实例。)

还请注意,在我的本地测试系统上,无论我重新运行查询多少次,查询都将在0.02秒内运行。

以下是查询(从实际搜索页面生成的示例):

SELECT 
    `cc6177_clients`.*,
    ACOS(SIN(RADIANS(`b1e39c_client_lat`)) * SIN(RADIANS(51.0486151)) + COS(RADIANS(`b1e39c_client_lat`)) * COS(RADIANS(51.0486151)) * COS(RADIANS(`b1e39c_client_long`) - RADIANS(- 114.0708459))) * 3964
          AS `distance`
FROM
    `cc6177_clients`
WHERE
    (b1e39c_client_status = '1'
        AND b1e39c_client_profile_status = '1'
        AND b1e39c_client_type = 'provider')
GROUP BY `b1e39c_client_id`
HAVING (distance <= 50)
ORDER BY `b1e39c_client_company_name` ASC
LIMIT 8

这是EXPLAIN输出:

1   SIMPLE  cc6177_clients  ref PRIMARY,client_email,client_company_name,main_search    main_search 3   const,const,const   26564   Using index condition; Using where; Using filesort  

这是创建表:

CREATE TABLE `cc6177_clients` (
 `b1e39c_client_id` int(11) NOT NULL AUTO_INCREMENT,
 `b1e39c_client_type` enum('client','provider') COLLATE utf8_unicode_ci NOT NULL,
 `b1e39c_client_login_type` enum('normal','social') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'normal',
 `b1e39c_client_oauth_provider` enum('facebook','gplus') COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_oauth_id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_access_token` text COLLATE utf8_unicode_ci,
 `b1e39c_client_referrer_key` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_nickname` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_email` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_password` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `b1e39c_client_first_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_last_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_picture` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_country_code` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_contact_number` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_address` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_lat` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_long` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_city` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_state` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_postal_code` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_status` enum('0','1') COLLATE utf8_unicode_ci NOT NULL DEFAULT '1' COMMENT '0=>Not Active,1=>Active',
 `b1e39c_client_activation_key` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'It is used for account activation or reset password request key',
 `b1e39c_client_verified` enum('0','1') COLLATE utf8_unicode_ci NOT NULL DEFAULT '0' COMMENT 'It is used to verify client email address(0=>not Verified,1=>Verified)',
 `b1e39c_client_registered_on` datetime NOT NULL,
 `b1e39c_client_login_failed_count` int(2) NOT NULL,
 `b1e39c_client_login_failed_time` datetime DEFAULT NULL,
 `b1e39c_client_login_ip` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_last_login` datetime DEFAULT NULL,
 `b1e39c_client_view_status` enum('0','1') COLLATE utf8_unicode_ci NOT NULL,
 `b1e39c_client_delete_status` enum('0','1') COLLATE utf8_unicode_ci NOT NULL DEFAULT '1' COMMENT '0=>client deleted, 1=> client active',
 `b1e39c_client_verify_email_link_exp` datetime DEFAULT NULL,
 `b1e39c_client_company_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_website_address` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_company_logo` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'Provider Company Logo',
 `b1e39c_client_desc` text COLLATE utf8_unicode_ci,
 `b1e39c_client_category_id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `b1e39c_client_sub_category_id` int(11) DEFAULT NULL,
 `b1e39c_client_claim_option` enum('0','1','2') COLLATE utf8_unicode_ci NOT NULL DEFAULT '0' COMMENT '0=>default,1=>User Added By Admin,2=>claim then make main provider',
 `b1e39c_client_membership_id` int(11) DEFAULT NULL COMMENT 'client current membership table unique id',
 `b1e39c_client_cur_membership_id` int(11) DEFAULT NULL COMMENT 'client currency membership',
 `b1e39c_client_membership_type` enum('free','paid') COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'client membership type',
 `b1e39c_client_profile_status` enum('0','1') COLLATE utf8_unicode_ci NOT NULL DEFAULT '0',
 `b1e39c_client_profile_cover` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 PRIMARY KEY (`b1e39c_client_id`),
 UNIQUE KEY `client_email` (`b1e39c_client_email`),
 KEY `client_company_name` (`b1e39c_client_company_name`),
 KEY `main_search` (`b1e39c_client_status`,`b1e39c_client_profile_status`,`b1e39c_client_type`)
) ENGINE=InnoDB AUTO_INCREMENT=55931 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

1 个答案:

答案 0 :(得分:0)

不要在各处使用VARCHAR(255);使用合理的限制。 (这将有助于提高当前所需的临时表的性能。

WHERE子句中使用“边界框”,再加上INDEX(lat), INDEX(long)。 (请参见下文。)

不要使带有常量前缀(b1e39c_client_)的SQL混乱。 (人类的东西。)

摆脱GROUP BY;除了减慢查询速度外,它不会向 this 查询添加任何内容。 (这消除了不必要的数据传递。)

没有一个可以解释为什么第一次运行比下一次运行快得多的原因。

“边界框”类似于

 AND lat  BETWEEN .. AND ..
 AND long BETWEEN .. AND ..

,其中值填充为距源纬度/经度50个单位。 (请注意,long测试需要用cosd(lat)除。)

这将使查询速度提高一个数量级,从而使其变得如此之快,以至于您原来的问题变得毫无意义。

在没有边界框的情况下,这可能会有所帮助:

INDEX(status, profile_status, type,   -- in any order
      company_name)   -- last

如果您想研究原始问题,请查看是否可以让EXPLAIN SELECT ...显示两个不同的输出。