mysql - 根据经纬度查找用户

标签 mysql sql oracle query-performance

我想找到 5 英里以内且具有与我相同标签的用户。

我的数据结构:

UserTable

--------------------------------------
 userid | name | lat | long | address
--------------------------------------
  101   |  xyz |  92 |  72  | NY
  201   |  HYS |  48 |  56  | JAMAICA
  301   |  LMN |  92 |  75  | Brazil


TagTable

---------------------
 id | userid | tagid
---------------------
  1 |   101  |   5
  2 |   201  |   7
  3 |   301  |   5

查询:

SELECT vb.userid,
       vb.address,
       ( 6371 * ACOS(   COS( RADIANS( 28.684342 ) )
                          * COS( RADIANS( vb.lat ) ) 
                          * COS( RADIANS( vb.long) - RADIANS( 77.137941 ) )
                      + SIN( RADIANS( 28.684342 ) )
                          * SIN( RADIANS( vb.lat) )
                    )
       ) AS distance
  FROM UserTable vb, TagTable vk
 WHERE vk.userid = vb.userid
   AND vk.tagid = '5'
 GROUP BY vk.userid
HAVING distance < 10
 ORDER BY distance;

上面的查询要花很多时间,请帮我找到这种情况下最快的查询。

最佳答案

使用 Oracle 的 Spatial数据

SQL Fiddle

Oracle 11g R2 架构设置:

CREATE TABLE UserTable (
  userid   NUMBER(8,0),
  name     VARCHAR2(255),
  location SDO_GEOMETRY,
  address  VARCHAR2(255)
);

INSERT INTO UserTable
          SELECT 101, 'xyz', SDO_GEOMETRY( 2001, 8307, SDO_POINT_TYPE(92,72,NULL), NULL, NULL), 'NY' FROM DUAL
UNION ALL SELECT 201, 'HYS', SDO_GEOMETRY( 2001, 8307, SDO_POINT_TYPE(48,56,NULL), NULL, NULL), 'JAMACA' FROM DUAL
UNION ALL SELECT 301, 'LMN', SDO_GEOMETRY( 2001, 8307, SDO_POINT_TYPE(92,75,NULL), NULL, NULL), 'Brazil' FROM DUAL;

INSERT INTO USER_SDO_GEOM_METADATA (
  TABLE_NAME, COLUMN_NAME, DIMINFO, SRID
) VALUES (
  'USERTABLE',
  'LOCATION', 
  SDO_DIM_ARRAY(
    SDO_DIM_ELEMENT('LONG', -180.0, 180.0, 0.5), 
    SDO_DIM_ELEMENT('LAT', -90.0, 90.0, 0.5)
  ), 
  8307
);

CREATE INDEX UserTable_SIDX ON UserTable( location ) INDEXTYPE IS MDSYS.SPATIAL_INDEX;

CREATE TABLE TagTable (id, userid, tagid ) AS
          SELECT 1, 101, 5 FROM DUAL
UNION ALL SELECT 2, 201, 7 FROM DUAL
UNION ALL SELECT 3, 301, 5 FROM DUAL;

查询 1:

SELECT u.userid
FROM   UserTable u
       INNER JOIN
       TagTable t
       ON u.UserID = t.UserID
WHERE  sdo_within_distance (
         u.location,
         SDO_GEOMETRY( 2001, 8307, SDO_POINT_TYPE(92,72,NULL), NULL, NULL),
         'distance=5 unit=MILE'
       ) = 'TRUE'
AND    t.tagid = 5

Results :

| USERID |
|--------|
|    101 |

关于mysql - 根据经纬度查找用户,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33256674/

相关文章:

mysql - 使用SQL从两行的最大值中选择唯一的记录

php - Laravel 4 - 模型和一对多

sql - 解决 SQL "The network path was not found"错误

sql - Oracle 是否有相当于 SQL Server OUTPUT INSERTED.* 的功能?

sql - 列名以数字开头?

php - 在 yii2 中插入数据库?

mysql - 使用 Liquibase 添加创建日期 - 与数据库无关

mysql - 如何从两个以上的表中收集数据并将结果放入新表中

mysql - 选择并总结具有相似行的所有记录满足条件的唯一行

sql - 在部分xpath上的Oracle 10.2.0.4.0查询