mysql实现地理位置搜索_MySQL
随着LBS应用的遍地开花,在数据库中实现基于地理位置的搜索显得尤为重要.今天研究了下,顺便做个小结.
首先设计好一个简单的数据表,用来存放经纬度信息:
<code>CREATE TABLE `index` ( `id` int(11) NOT NULL AUTO_INCREMENT, `lat` double NOT NULL, `lng` double NOT NULL, PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8;</code>
创建完成后我们可以查看一下,应该是这个样子
<code>mysql> desc `index`;+-------+---------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+-------+---------+------+-----+---------+----------------+| id | int(11) | NO | PRI | NULL | auto_increment || lat | double | NO | | NULL | || lng | double | NO | | NULL | |+-------+---------+------+-----+---------+----------------+3 rows in set (0.00 sec)</code>
接着我们来制造点儿数据,便于等下测试,写了个python脚本来实现:
<code>import MySQLdbimport randomtry: conn=MySQLdb.connect(host='localhost',user='eslizn',passwd='123456',db='geo',port=3306) cur=conn.cursor() for i in range(2000000): lat = random.randint(-9000000,9000000)/100000.0 lng = random.randint(-18000000,18000000)/100000.0 sql = "insert into `index` (`lat`,`lng`) values (%f,%f)" % (lat,lng) cur.execute(sql) print "[%d]%s" % (i,sql) cur.close() conn.close()except MySQLdb.Error,e: print "Mysql Error %d: %s" % (e.args[0], e.args[1])</code>
为了便于等下测试添加索引和没有添加索引的效果,还需要复制一份表出来做对照:
<code>mysql> create table unindex select * from `index`;Query OK, 2000838 rows affected (0.93 sec)Records: 2000838 Duplicates: 0 Warnings: 0</code>
对index表的lat,lng字段设置一个B-tree索引:
<code>mysql> ALTER TABLE `index` ADD INDEX `lat_lng` USING BTREE (`lat`, `lng`) ;Query OK, 2000838 rows affected (10.94 sec)Records: 2000838 Duplicates: 0 Warnings: 0</code>
根据两点的经纬度计算其距离以前也做过,不过毕竟图样,直接就拿平面上的那一套弄上了,这样简直就是大错特错,首先,虽然纬度转换成距离是乘以一个常量,但是计算经度的距离则是需要通过三角函数来计算,具体计算公式如下:
<code>R = earth’s radiusΔlat = lat2 lat1Δlng = lng2 lng1a = sin(Δlat/2) + cos(lat1) * cos(lat2) * sin(Δlng/2)c = 2*atan2(√a, √(1a))dist = R*c</code>
根据公式编写Sql查询语句:
<code>mysql> set @er=6366.564864;#earth’s radius (km)Query OK, 0 rows affected (0.00 sec)mysql> set @lat=56.14262; #Search origin latQuery OK, 0 rows affected (0.00 sec)mysql> set @lng=37.605853; #Search origin lngQuery OK, 0 rows affected (0.00 sec)mysql> set @dist=20;#Search radius (km)Query OK, 0 rows affected (0.00 sec)mysql> SELECT id,lat,lng,@er*2*ASIN(SQRT(POWER(SIN((@lat - lat)*pi()/180 / 2), 2) + COS(@lat * pi()/180) * COS(lat * pi()/180) * POWER(SIN((@lng - lng) * pi()/180 / 2), 2) )) as dist FROM `unindex` having dist </code>
虽然实现了查询,但是时间着实蛋疼(由于没有设置条件,mysql进行了表扫描,约200万条记录,你说疼不疼).所以必须修改下思路,圈出大致范围后进行查询.
首先要计算出经纬度范围,由于经度这个bitch的存在,我们又得进行三角函数计算:
<code>set @lat=56.14262;set @lng=37.605853;set @dist=20;#kmset @lat_length=20003.93/180;#lat lengthset @lat_left=@lat-(@dist/@lat_length);set @lat_right=@lat+(@dist/@lat_length);set @lng_left=@lng-@dist/abs(cos(radians(@lat))*@lat_length);set @lng_right=@lng+@dist/abs(cos(radians(@lat))*@lat_length);</code>
进行查询:
<code>mysql> set @er=6366.564864;#kmQuery OK, 0 rows affected (0.00 sec)mysql> set @lat=56.14262;Query OK, 0 rows affected (0.00 sec)mysql> set @lng=37.605853;Query OK, 0 rows affected (0.00 sec)mysql> set @dist=20;#kmQuery OK, 0 rows affected (0.00 sec)mysql> set @lat_length=20003.93/180;#lat lengthQuery OK, 0 rows affected (0.00 sec)mysql> set @lat_left=@lat-(@dist/@lat_length);Query OK, 0 rows affected (0.00 sec)mysql> set @lat_right=@lat+(@dist/@lat_length);Query OK, 0 rows affected (0.00 sec)mysql> set @lng_left=@lng-@dist/abs(cos(radians(@lat))*@lat_length);Query OK, 0 rows affected (0.00 sec)mysql> set @lng_right=@lng+@dist/abs(cos(radians(@lat))*@lat_length);Query OK, 0 rows affected (0.00 sec)mysql> SELECT id,lat,lng,@er*2*ASIN(SQRT(POWER(SIN((@lat - lat)*pi()/180 / 2), 2) + COS(@lat * pi()/180) * COS(lat * pi()/180) * POWER(SIN((@lng - lng) * pi()/180 / 2), 2) )) as dist FROM `unindex` WHERE lat BETWEEN @lat_left AND @lat_right AND lng BETWEEN @lng_left AND @lng_right having dist </code>
通过结果可以看出查询结果有很大的改善,但是事实上我们还可以进行优化,因为我们现在所操作的是没有建立索引的数据表,接下来我们改用建立过索引的数据表看看效果:
<code>mysql> set @er=6366.564864;#kmQuery OK, 0 rows affected (0.00 sec)mysql> set @lat=56.14262;Query OK, 0 rows affected (0.00 sec)mysql> set @lng=37.605853;Query OK, 0 rows affected (0.00 sec)mysql> set @dist=20;#kmQuery OK, 0 rows affected (0.00 sec)mysql> set @lat_length=20003.93/180;#lat lengthQuery OK, 0 rows affected (0.00 sec)mysql> set @lat_left=@lat-(@dist/@lat_length);Query OK, 0 rows affected (0.00 sec)mysql> set @lat_right=@lat+(@dist/@lat_length);Query OK, 0 rows affected (0.00 sec)mysql> set @lng_left=@lng-@dist/abs(cos(radians(@lat))*@lat_length);Query OK, 0 rows affected (0.00 sec)mysql> set @lng_right=@lng+@dist/abs(cos(radians(@lat))*@lat_length);Query OK, 0 rows affected (0.00 sec)mysql>mysql> SELECT id,lat,lng,@er*2*ASIN(SQRT(POWER(SIN((@lat - lat)*pi()/180 / 2), 2) + COS(@lat * pi()/180) * COS(lat * pi()/180) * POWER(SIN((@lng - lng) * pi()/180 / 2), 2) )) as dist FROM `index` WHERE lat BETWEEN @lat_left AND @lat_right AND lng BETWEEN @lng_left AND @lng_right having dist </code>
至此,我们就实现了一个类似微信的"查看附近的人"的功能

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











이 기사는 MySQL의 Alter Table 문을 사용하여 열 추가/드롭 테이블/열 변경 및 열 데이터 유형 변경을 포함하여 테이블을 수정하는 것에 대해 설명합니다.

기사는 인증서 생성 및 확인을 포함하여 MySQL에 대한 SSL/TLS 암호화 구성에 대해 설명합니다. 주요 문제는 자체 서명 인증서의 보안 영향을 사용하는 것입니다. [문자 수 : 159]

기사는 MySQL에서 파티셔닝, 샤딩, 인덱싱 및 쿼리 최적화를 포함하여 대규모 데이터 세트를 처리하기위한 전략에 대해 설명합니다.

기사는 MySQL Workbench 및 Phpmyadmin과 같은 인기있는 MySQL GUI 도구에 대해 논의하여 초보자 및 고급 사용자를위한 기능과 적합성을 비교합니다. [159 자].

이 기사에서는 Drop Table 문을 사용하여 MySQL에서 테이블을 떨어 뜨리는 것에 대해 설명하여 예방 조치와 위험을 강조합니다. 백업 없이는 행동이 돌이킬 수 없으며 복구 방법 및 잠재적 생산 환경 위험을 상세하게합니다.

기사는 외국 열쇠를 사용하여 데이터베이스의 관계를 나타내고 모범 사례, 데이터 무결성 및 피할 수있는 일반적인 함정에 중점을 둡니다.

이 기사에서는 PostgreSQL, MySQL 및 MongoDB와 같은 다양한 데이터베이스에서 JSON 열에서 인덱스를 작성하여 쿼리 성능을 향상시킵니다. 특정 JSON 경로를 인덱싱하는 구문 및 이점을 설명하고 지원되는 데이터베이스 시스템을 나열합니다.

기사는 준비된 명령문, 입력 검증 및 강력한 암호 정책을 사용하여 SQL 주입 및 무차별 적 공격에 대한 MySQL 보안에 대해 논의합니다 (159 자)
