Find User on Basis of Lat long

耗尽温柔 提交于 2019-12-13 05:19:51

问题


I want to find users which are under 5 miles location and having the same tag that I have.

The structure of my data:

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

Query:

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;

The above query is taking lot of time, kindly help me to find the fastest query for this scenario.


回答1:


If indexing doesn't make a big difference I might try and take some of the heavy computational steps out, and see how that improves efficiency:

Idea 1: remove the ORDER BY clause, and instead sort in PHP.

Idea 2: then also remove the HAVING clause, and instead filter in PHP as you loop through the results.

Idea 3: If a userid can only appear once for a particular tagid in TagTable, remove the whole GROUP BY clause, and add the distance test into the WHERE clause.

I'm not sure if passing off some of the processing to PHP would help efficiency, by it's worth testing at least.




回答2:


Use Oracle's Spatial data

SQL Fiddle

Oracle 11g R2 Schema Setup:

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;

Query 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 |


来源:https://stackoverflow.com/questions/33256674/find-user-on-basis-of-lat-long

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!