我想找到位于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;
以上查询需要花费大量时间,请帮助我找到最快的查询方案。
答案 0 :(得分:2)
使用Oracle的Spatial数据
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 |
答案 1 :(得分:1)
如果索引没有产生很大的影响,我可能会尝试采取一些重要的计算步骤,并看看它如何提高效率:
创意1:删除ORDER BY
子句,改为用PHP排序。
创意2:然后还删除HAVING
子句,而不是在循环结果时在PHP中过滤。
创意3:如果userid
只能针对tagid
中的特定TagTable
显示一次,请移除整个GROUP BY
子句,并将距离测试添加到WHERE
中{1}}条款。
我不确定是否将一些处理权交给PHP会有助于提高效率,至少值得测试。