我们有一个在MariaDB mariadb-5.5.37-1.el7_0.x86_64上查找IP地理位置的表,如下所示:
创建表
ip2location_db24(idint(11)非空AUTO_INCREMENT,ip_fromint(10)无符号默认空,ip_toint(10)无符号默认空,country_codechar(2)整理utf8_bin默认NULL,country_namevarchar(64)整理utf8_bin默认NULL,region_namevarchar(128)整理utf8_bin默认NULL,city_namevarchar(128)整理utf8_bin默认NULL,latitude双默认值为空,longitude双默认值为空,zip_codevarchar(30)整理utf8_bin默认NULL,time_zonevarchar(8)整理utf8_bin默认NULL,ispvarchar(255)整理utf8_bin默认NULL,domainvarchar(128)整理utf8_bin默认NULL,net_speedvarchar(8)整理utf8_bin默认NULL,idd_codevarchar(5)整理utf8_bin默认NULL,area_codevarchar(30)整理utf8_bin默认NULL,weather_station_codevarchar(10)整理utf8_bin默认NULL,weather_station_namevarchar(128)整理utf8_bin默认NULL,mccvarchar(256)整理utf8_bin默认NULL,mncvarchar(256)整理utf8_bin默认NULL,mobile_brandvarchar(128)整理utf8_bin默认NULL,elevationint(10)默认为空,usage_typevarchar(11)整理utf8_bin默认NULL, 主键(id), KEYidx_ip_from(ip_from) KEYidx_latitude(latitude) KEYidx_longitude(longitude) KEYidx_ip_from_to_2(ip_to,ip_from) ) ENGINE=InnoDB AUTO_INCREMENT=9541211默认CHARSET=utf8 COLLATE=utf8_bin
ip_from和ip_to列定义了每个地理位置的起始和结束边界。
我们在这张表上有大约一千万份记录。
当查询给定IP的geo位置时,我们发现服务器在以下SQL中存在严重的性能问题:
从ip2location_db24中选择*,其中ip_to >=1908980838和ip_from <=1908980838限制为1;*行* id: 5475739 ip_from: 1908932608 ip_to: 1909063679 country_code: CN country_name:中国 region_name:山西 city_name:太原 纬度: 37.86944 经度: 112.56028 zip_code:- time_zone:+08:00 isp:中国联通陕西省网络 域: CHINAUNICOM.COM net_speed: DSL idd_code: 86 area_code: 0351 weather_station_code: CHXX0129 weather_station_name:太原 管理协委会: 460 跨国公司: 01/06 mobile_brand:中国联通 海拔: 787 usage_type: ISP/MOB 一排设置(15.08秒)
但是,当使用以下等价SQL进行查询时,其速度非常快。
从ip2location_db24 ip_from <=1908980838命令中选择* ip_from限制限制1 \G *行* id: 5475739 ip_from: 1908932608 ip_to: 1909063679 country_code: CN country_name:中国 region_name:山西 city_name:太原 纬度: 37.86944 经度: 112.56028 zip_code:- time_zone:+08:00 isp:中国联通陕西省网络 域: CHINAUNICOM.COM net_speed: DSL idd_code: 86 area_code: 0351 weather_station_code: CHXX0129 weather_station_name:太原 管理协委会: 460 跨国公司: 01/06 mobile_brand:中国联通 海拔: 787 usage_type: ISP/MOB 一排设定(0.00秒)
问题是,当我们签出执行计划时,两个查询对ip_from列的索引使用相同的范围扫描。但这两个SQL的性能远非如此。有谁知道原因吗?
为了提供更多信息,我们还测试了其输出列被索引完全覆盖的查询。
MariaDB ip2location从ip2location_db24中选择ip_from、ip_to,其中ip_to >=1908980838和ip_from <=1908980838限制为1; + ip_from \x{e76f} ip_to \x{e76f} + 1908932608 x 1909063679 x + 一排设置(0.01秒)
注意,上面的查询SQL速度非常快。但是,当查询没有索引覆盖的任何额外列时,需要难以置信的长时间:
MariaDB ip2location从ip2location_db24中选择ip_from、ip_to、country_code,其中ip_to >=1908980838和ip_from <=1908980838限制为1; + ip_from,ip_to,country_code,country_code + \x{e76f} 1908932608 \ 1909063679 CN = + 一排设置(10.15秒)
发布于 2014-11-16 00:11:23
select * from ip2location_db24 where ip_to >=1908980838 and ip_from <=1908980838 limit 1; 比较慢,因为比较两列。
select * from ip2location_db24 where ip_from <=1908980838 order by ip_from desc limit 1 因为只比较了一个索引列,所以速度很快。
发布于 2014-11-18 08:11:16
尝试force index,如MariaDB手册https://mariadb.com/kb/en/mariadb/documentation/optimization-and-tuning/query-optimizations/how-to-force-query-plans/#dont-use-a-particular-index部分所述
select ip_from,ip_to,country_code
from ip2location_db24 force index (idx_ip_from_to_2)
where ip_to >=1908980838 and ip_from <=1908980838
limit 1;https://stackoverflow.com/questions/26773388
复制相似问题