Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 使用SQL、地理坐标和半径查询重叠区域_Mysql_Sql_Query Optimization - Fatal编程技术网

Mysql 使用SQL、地理坐标和半径查询重叠区域

Mysql 使用SQL、地理坐标和半径查询重叠区域,mysql,sql,query-optimization,Mysql,Sql,Query Optimization,我有一个MySQL数据集,它由纬度、经度和一个值组成。我试图将其纬度和经度坐标在其他纬度和经度坐标的给定半径内的值相加(让我们称之为“焦点”)。最棘手的是,我试图从重叠区域中分离出不同的坐标-例如,半径1与半径2重叠的区域 有半径的每个焦点都有多个半径“区域”,因此对于任意给定的一组横向/纵向坐标,可以总结出很多东西。我成功地完成了一个查询,虽然有点慢,但基本上是有效的: Select Sum(If(`zone`='z0_0x1_0',`value`,0)) a

我有一个MySQL数据集,它由纬度、经度和一个值组成。我试图将其纬度和经度坐标在其他纬度和经度坐标的给定半径内的值相加(让我们称之为“焦点”)。最棘手的是,我试图从重叠区域中分离出不同的坐标-例如,半径1与半径2重叠的区域

有半径的每个焦点都有多个半径“区域”,因此对于任意给定的一组横向/纵向坐标,可以总结出很多东西。我成功地完成了一个查询,虽然有点慢,但基本上是有效的:

    Select 
            Sum(If(`zone`='z0_0x1_0',`value`,0)) as `z0_0x1_0`,
            Sum(If(`zone`='z0_0x1_1',`value`,0)) as `z0_0x1_1`,
            Sum(If(`zone`='z0_0x1_2',`value`,0)) as `z0_0x1_2`,
            Sum(If(`zone`='z0_0x1_3',`value`,0)) as `z0_0x1_3`,
            Sum(If(`zone`='z0_1x1_0',`value`,0)) as `z0_1x1_0`,
            Sum(If(`zone`='z0_1x1_1',`value`,0)) as `z0_1x1_1`,
            Sum(If(`zone`='z0_1x1_2',`value`,0)) as `z0_1x1_2`,
            Sum(If(`zone`='z0_2x1_0',`value`,0)) as `z0_2x1_0`,
            Sum(If(`zone`='z0_2x1_1',`value`,0)) as `z0_2x1_1`,
            Sum(If(`zone`='z0_3x1_0',`value`,0)) as `z0_3x1_0`,
            Sum(If(`zone`='z0_3x1_1',`value`,0)) as `z0_3x1_1`,
            Sum(If(`zone`='z0_0',`value`,0)) as `z0_0`,
            Sum(If(`zone`='z0_1',`value`,0)) as `z0_1`,
            Sum(If(`zone`='z0_2',`value`,0)) as `z0_2`,
            Sum(If(`zone`='z0_3',`value`,0)) as `z0_3`,
            Sum(If(`zone`='z1_0',`value`,0)) as `z1_0`,
            Sum(If(`zone`='z1_1',`value`,0)) as `z1_1`,
            Sum(If(`zone`='z1_2',`value`,0)) as `z1_2`,
            Sum(If(`zone`='z1_3',`value`,0)) as `z1_3` 
    From  
        (Select `lat`, `lng`, `value`,  
                Case 
                            When ((`dist_0` Between 2.8723597844095 And 4.3343662110324) And (`dist_1` Between 3.6260179152491 And 5.4681062617155)) Then 'z0_0x1_0' 
                            When ((`dist_0` Between 2.8723597844095 And 4.3343662110324) And (`dist_1` Between 2.1278369006061 And 3.6260179152491)) Then 'z0_0x1_1' 
                            When ((`dist_0` Between 2.8723597844095 And 4.3343662110324) And (`dist_1` Between 1.3333495959677 And 2.1278369006061)) Then 'z0_0x1_2' 
                            When ((`dist_0` Between 2.8723597844095 And 4.3343662110324) And (`dist_1` Between 0 And 1.3333495959677)) Then 'z0_0x1_3' 
                            When ((`dist_0` Between 1.68658498678 And 2.8723597844095) And (`dist_1` Between 3.6260179152491 And 5.4681062617155)) Then 'z0_1x1_0' 
                            When ((`dist_0` Between 1.68658498678 And 2.8723597844095) And (`dist_1` Between 2.1278369006061 And 3.6260179152491)) Then 'z0_1x1_1' 
                            When ((`dist_0` Between 1.68658498678 And 2.8723597844095) And (`dist_1` Between 1.3333495959677 And 2.1278369006061)) Then 'z0_1x1_2' 
                            When ((`dist_0` Between 1.0573158612197 And 1.68658498678) And (`dist_1` Between 3.6260179152491 And 5.4681062617155)) Then 'z0_2x1_0' 
                            When ((`dist_0` Between 1.0573158612197 And 1.68658498678) And (`dist_1` Between 2.1278369006061 And 3.6260179152491)) Then 'z0_2x1_1' 
                            When ((`dist_0` Between 0 And 1.0573158612197) And (`dist_1` Between 3.6260179152491 And 5.4681062617155)) Then 'z0_3x1_0' 
                            When ((`dist_0` Between 0 And 1.0573158612197) And (`dist_1` Between 2.1278369006061 And 3.6260179152491)) Then 'z0_3x1_1' 
                            When ((`dist_0` Between 2.8723597844095 And 4.3343662110324)) Then 'z0_0' 
                            When ((`dist_0` Between 1.68658498678 And 2.8723597844095)) Then 'z0_1' 
                            When ((`dist_0` Between 1.0573158612197 And 1.68658498678)) Then 'z0_2' 
                            When ((`dist_0` Between 0 And 1.0573158612197)) Then 'z0_3' 
                            When ((`dist_1` Between 3.6260179152491 And 5.4681062617155)) Then 'z1_0' 
                            When ((`dist_1` Between 2.1278369006061 And 3.6260179152491)) Then 'z1_1' 
                            When ((`dist_1` Between 1.3333495959677 And 2.1278369006061)) Then 'z1_2' 
                            When ((`dist_1` Between 0 And 1.3333495959677)) Then 'z1_3' 
                End As `zone`

                From 
                    (Select `lat`, `lng`, `value`,
                        (acos(0.65292272498833*sin(radians(`lat`)) + 0.75742452772129*cos(radians(`lat`))*cos(radians(`lng`)-(-1.2910922519714))) * 6371) as `dist_0`,
                        (acos(0.65251345816785*sin(radians(`lat`)) + 0.75777713538338*cos(radians(`lat`))*cos(radians(`lng`)-(-1.2916315412569))) * 6371) as `dist_1` 
                    From `pop`
                    Where
                        ((`lat` Between 40.714353892125 And 40.810300107875) And (`lng` Between -74.037474145971 And -73.910799854029)) Or 
                        ((`lat` Between 40.673205922895 And 40.789544077105) And (`lng` Between -74.081798776797 And -73.928273223203))
                    )
                As FirstCut
        )
        As Zonecut 
这是事情的逻辑:

  • 首先,它获取每个焦点的最大半径周围的边界框。(这是第一次查询。)这将我们正在查看的数据点数量减少了几个数量级

  • 然后它处理所有这些数据,并获取每个数据点与焦点的距离(在本例中,
    dist_0
    dist_1
    ,但可以有任意数量的焦点-我在本例中使用了两个,只是为了说明其工作原理)。这是大圆距离的哈弗公式

  • 然后Case语句开始,为每个坐标指定一个“区域”的成员,该区域从最复杂到最不复杂进行处理。分区代码仅表示“X区,半径Y”-“z0_1”表示“0区,半径1”。如果有一个“x”,则表示它是多个分区的交点。这个“区号”只是作为字符串分配的

  • 最后,通过分配区域名称和那些sum(If())语句,区域代码用于汇总所有内容。(无论出于何种原因,If()的工作速度似乎略快于这里的Case()

  • 它向我的脚本(PHP)输出区域和总和的列表。现在很明显,整个过程都是按程序生成的,因为您必须提前计算所有可能的区域,这些区域实际上会有“点击”,这都是作为预处理来完成的,以避免在SQL中执行

    有没有更聪明的方法?我给他们分配一个字符串的位,然后将该字符串过滤到字段中。。。它看起来很粗糙,不是很优雅。但我找不到更好的方法将它们分类到一个大型Case语句中的字段中(这似乎比许多Case语句快得多)


    对此的任何和所有反馈都将不胜感激。MySQL表是海量的(数百万行),并且索引到所有神圣的地狱。运行上面的查询大约需要0.6秒,这还不算太糟糕,但是随着更多的焦点被添加,查询开始需要更长的时间,在这个阶段,我只是在尝试通过SQL逻辑来思考。谢谢。

    我没有彻底检查过,但这似乎可以缩短那个大的
    案例
    一些:

    CONCAT(
        ( CASE
            WHEN (dist_0 ... ) THEN 'z0_0'
            WHEN (dist_0 ... ) THEN 'z0_1'
            ...
            ELSE '' ),
        ( CASE
            WHEN (dist_1 ... ) THEN 'z1_0'
            WHEN (dist_1 ... ) THEN 'z1_1'
            ...
            ELSE '' ) )  AS zone
    

    哦,那太聪明了。我会看看是否可以实施;我认为这是可行的。