AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 158349
Accepted
xangr
xangr
Asked: 2016-12-17 02:40:01 +0800 CST2016-12-17 02:40:01 +0800 CST 2016-12-17 02:40:01 +0800 CST

Como posso agilizar minha consulta em processos de geolocalização

  • 772

Tenho uma tabela que contém 10.301.390 registros de GPS, cidades, países e blocos de endereços IP. Eu tenho a localização atual do usuário com latitude e longitude. Eu criei esta consulta:

SELECT
  *, point(45.1013021, 46.3021011) <@> point(latitude, longitude) :: point AS distance
FROM
  locs
WHERE
  (
    point(45.1013021, 46.3021011) <@> point(latitude, longitude)
  ) < 10 -- radius
ORDER BY
  distance LIMIT 1;

Esta consulta me deu com sucesso o que eu quero, mas é lento. Demorou 2 a 3 segundos para obter um registro por determinada latitude e longitude.

Eu tentei um índice B-Tree nas colunas latitudee , também tentei, mas ainda assim a consulta é lenta.longitudeGIST( point(latitude, longitude));

Como posso acelerar esta consulta?

Atualizar:

Parece que a lentidão é causada pelo ORDER BYmas eu quero obter a distância mais curta, então a questão permanece.

postgresql index
  • 2 2 respostas
  • 6556 Views

2 respostas

  • Voted
  1. Best Answer
    joanolo
    2016-12-17T14:50:16+08:002016-12-17T14:50:16+08:00

    Você pode considerar o uso de um índice GIST com base no uso da função ll_to_earth. Este índice permitirá pesquisas "próximas" rápidas.

    CREATE INDEX 
       ON locs USING gist (ll_to_earth(lat, lng));
    

    Depois de ter esse índice, sua consulta deve ser feita de uma maneira diferente.

    Seus pares (lat, lng) precisam ser convertidos para o earthtipo e comparados com os valores indexados (que são do mesmo tipo). Sua consulta precisará ter duas condições, uma para o resultado "aproximado" e outra para o "preciso". O primeiro poderá usar o índice anterior:

    SELECT
        *
    FROM
        locs
    WHERE
        /* First condition allows to search for points at an approximate distance:
           a distance computed using a 'box', instead of a 'circumference'.
           This first condition will use the index.
           (45.1013021, 46.3021011) = (lat, lng) of search center. 
           25000 = search radius (in m)
        */
        earth_box(ll_to_earth(45.1013021, 46.3021011), 25000) @> ll_to_earth(lat, lng) 
    
        /* This second condition (which is slower) will "refine" 
           the previous search, to include only the points within the
           circumference.
        */
        AND earth_distance(ll_to_earth(45.1013021, 46.3021011), 
                 ll_to_earth(lat, lng)) < 25000 ;
    

    Para usar este código, você precisa de duas extensões (incluídas na maioria das distribuições do PostgreSQL):

    CREATE EXTENSION IF NOT EXISTS cube ;
    CREATE EXTENSION IF NOT EXISTS earthdistance;
    

    Esta é a documentação para eles:

    • cubo . Você deve dar uma olhada na descrição do operador @>. Este módulo é necessário para o próximo.
    • EarthDistance . Você encontrará aqui informações sobre earth_boxe earth_distance. Este módulo assume que a Terra é esférica, o que é uma aproximação boa o suficiente para a maioria das aplicações.

    Um teste com uma tabela composta por 2,2 milhões de linhas retiradas do Free World Cities Database me dá a seguinte resposta para a consulta anterior (que não é exatamente a mesma que a sua):

    "ru","andra-ata","Andra-Ata","24",,44.9509,46.3327
    "ru","andratinskiy","Andratinskiy","24",,44.9509,46.3327
    "ru","chernozemelskaya","Chernozemelskaya","24",,44.9821,46.0622
    "ru","gayduk","Gayduk","24",,44.9578,46.5244
    "ru","imeni beriya","Imeni Beriya","24",,45.0208,46.3906
    "ru","imeni kirova","Imeni Kirova","24",,45.2836,46.4847
    "ru","kumskiy","Kumskiy","24",,44.9821,46.0622
    "ru","kumskoy","Kumskoy","24",,44.9821,46.0622
    "ru","lopas","Lopas","17",,44.937,46.1833
    "ru","pyatogo dekabrya","Pyatogo Dekabrya","24",,45.1858,46.1656
    "ru","svetlyy erek","Svetlyy Erek","24",,45.0079,46.4408
    "ru","ulan tuk","Ulan Tuk","24",,45.1542,46.1097
    

    Para ter uma ideia de "ordem de grandeza" sobre temporizações: pgAdmin III está me dizendo que o tempo para obter esta resposta é 22 ms. (PostgreSQL 9.6.1 com parâmetros "out-of-the-box", em um Mac com Mac OS 10.12, Core i7, SSD)

    • 11
  2. Evan Carroll
    2016-12-17T15:52:26+08:002016-12-17T15:52:26+08:00

    Resposta alternativa com PostGIS

    Se você estiver usando 10 milhões de linhas. Você provavelmente precisará intensificar e atualizar para o PostGIS.

    1. Converta seus pontos em tipos de geografia. Presumo que estejam no SRID 4326 de qualquer maneira, se vierem do GPS. Para isso você pode usargeometery(point)::geography , ou se você armazenar em lat/long você pode usarST_MakePoint
    2. Crie um índice na nova coluna geom (de ST_Points)
    3. Então você quer usar ST_DWithin. Esta função irá um índice (se você criar um).
    4. Em seguida, calcule apenas os ST_Distancepontos na caixa delimitadora

    Aqui está o sinal para ST_DWithin,

    boolean ST_DWithin(geometry g1, geometry g2, double precision distance_of_srid);
    boolean ST_DWithin(geography gg1, geography gg2, double precision distance_meters);
    boolean ST_DWithin(geography gg1, geography gg2, double precision distance_meters, boolean use_spheroid);
    

    Ele pode medir sua distância ao longo do esferóide ou esfera.

    SELECT geom, ST_Distance(geom, point)
    WHERE ST_DWithin( geom, pointgiven, limit in meters )
    ORDER BY geom <=> point ASC
    LIMIT 1;
    
    • 3

relate perguntas

  • Quanto "Padding" coloco em meus índices?

  • Sequências Biológicas do UniProt no PostgreSQL

  • O que significa "índice" em RDBMSs? [fechado]

  • Como criar um índice condicional no MySQL?

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve