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 / 131898
Accepted
monoh_
monoh_
Asked: 2016-03-11 13:47:27 +0800 CST2016-03-11 13:47:27 +0800 CST 2016-03-11 13:47:27 +0800 CST

Armazenando rotas de ônibus em um banco de dados

  • 772

Fiz algumas pesquisas e descobri que devo armazenar uma rota como uma sequência de paradas. Algo como:

Start -> Stop A -> Stop B -> Stop C -> End

Criei três tabelas:

  • Rotas
  • paradas
  • Pontos de rota

...onde RouteStops é uma tabela de junção.

Eu tenho algo como:

Rotas

+---------+
| routeId |
+---------+
|    1    |
+---------+
|    2    |
+---------+

Estações

+-----------+------+
| stationId | Name |
+-----------+------+
|     1     |   A  |
+-----------+------+
|     2     |   B  |
+-----------+------+
|     3     |   C  |
+-----------+------+
|     4     |   D  |
+-----------+------+

RouteStations

+-------------+---------------+
| routeId(fk) | stationId(fk) |
+-------------+---------------+
|     1       |       A       |
+-------------+---------------+
|     1       |       C       |
+-------------+---------------+
|     1       |       D       |
+-------------+---------------+
|     2       |       A       |
+-------------+---------------+
|     2       |       D       |
+-------------+---------------+

A rota 1 passa por

Station A -> Station C -> Station D

A rota 2 passa por

Station A -> Station D

Esta é uma boa maneira de armazenar rotas?

De acordo com a Wikipédia :

[...] o sistema de banco de dados não garante nenhuma ordem das linhas, a menos que uma ORDER BYcláusula seja especificada [...]

Posso confiar em tal esquema de banco de dados ou talvez isso deva ser feito de maneira diferente?

Este é realmente o meu projeto universitário, então estou apenas imaginando se esse esquema pode ser considerado correto. Para este caso, eu provavelmente armazenaria apenas várias rotas (aproximadamente 3-5) e estações (aproximadamente 10-15), cada rota consistiria em cerca de 5 estações. Também ficaria feliz em saber como isso deve ser no caso de uma empresa de ônibus real e grande.

database-design
  • 4 4 respostas
  • 8686 Views

4 respostas

  • Voted
  1. Best Answer
    Nicolas de Fontenay
    2016-03-11T15:09:11+08:002016-03-11T15:09:11+08:00

    Para todas as análises de negócios que levam à arquitetura de banco de dados, recomendo escrever regras:

    • Uma rota tem 2 ou mais estações
    • Uma estação pode ser usada por muitas rotas
    • As estações em uma rota vêm em uma ordem específica

    A 1ª e a 2ª regras, como você notou, implicam em um relacionamento muitos para muitos, então você concluiu corretamente para criar routeStations.

    A terceira regra é a interessante. Isso implica que uma coluna extra é necessária para atender ao requisito. Para onde deve ir? Podemos ver que esta propriedade depende da Rota E da Estação. Portanto, ele deve estar localizado em routeStations.

    Eu adicionaria uma coluna à tabela routeStations chamada "stationOrder".

    +-------------+---------------+---------------
    | routeId(fk) | stationId(fk) | StationOrder |
    +-------------+---------------+---------------
    |     1       |       1       |       3      |
    +-------------+---------------+---------------
    |     1       |       3       |       1      |
    +-------------+---------------+---------------
    |     1       |       4       |       2      |
    +-------------+---------------+---------------
    |     2       |       1       |       1      |
    +-------------+---------------+---------------
    |     2       |       4       |       2      |
    +-------------+---------------+---------------
    

    Então a consulta se torna fácil:

    select rs.routeID,s.Name
    from routeStations rs
    join
    Stations s
    on rs.stationId=s.StationId
    where rs.routeId=1
    order by rs.StationOrder;
    
    +-------------+---------------+
    | routeId(fk) | stationId(fk) |
    +-------------+---------------+
    |     1       |       C       |
    +-------------+---------------+
    |     1       |       D       |
    +-------------+---------------+
    |     1       |       A       |
    +-------------+---------------+
    

    Notas:

    1. Corrigi o StationId em RouteStations no meu exemplo. Você está usando o StationName como o ID.
    2. Se você não usar um nome de rota, não há necessidade de routeId, pois você pode obtê-lo em routeStations
    3. Mesmo se você vincular à tabela de rotas, seu otimizador de banco de dados notará que não precisa desse link extra e simplesmente removerá as etapas extras.

    Para desenvolver no note 3, construí o caso de uso:

    Este é o Oracle 12c Enterprise.

    Observe que, no plano de execução abaixo, as rotas da tabela não são usadas. o Cost Base Optimizer (CBO) sabe que pode obter o routeId diretamente da chave primária de routeStations (etapa 5, INDEX RANGE SCAN em ROUTESTATIONS_PK, Predicate Information 5 - access("RS","ROUTEID"=1))

    --Table ROUTES
    create sequence routeId_Seq start with 1 increment by 1 maxvalue 9999999999999 cache 1000;
    
    CREATE TABLE routes
    (
      routeId  INTEGER NOT NULL
    );
    
    
    ALTER TABLE routes ADD (
      CONSTRAINT routes_PK
      PRIMARY KEY
      (routeId)
      ENABLE VALIDATE);
    
    insert into routes values (routeId_Seq.nextval);
    insert into routes values (routeId_Seq.nextval);
    commit;
    
    --TABLE STATIONS  
    create sequence stationId_seq start with 1 increment by 1 maxvalue 9999999999999 cache 1000;
    
    create table stations(
       stationID INTEGER NOT NULL,
       name varchar(50) NOT NULL
    );
    
    ALTER TABLE stations ADD (
      CONSTRAINT stations_PK
      PRIMARY KEY
      (stationId)
      ENABLE VALIDATE);
    
    insert into stations values (stationId_seq.nextval,'A');
    insert into stations values (stationId_seq.nextval,'B');
    insert into stations values (stationId_seq.nextval,'C');
    insert into stations values (stationId_seq.nextval,'D');
    commit;
    --
    
    --Table ROUTESTATIONS 
    CREATE TABLE routeStations
    (
      routeId       INTEGER NOT NULL,
      stationId     INTEGER NOT NULL,
      stationOrder  INTEGER NOT NULL
    );
    
    
    ALTER TABLE routeStations ADD (
      CONSTRAINT routeStations_PK
      PRIMARY KEY
      (routeId, stationId)
      ENABLE VALIDATE);
    
    ALTER TABLE routeStations ADD (
      FOREIGN KEY (routeId) 
      REFERENCES ROUTES (ROUTEID)
      ENABLE VALIDATE,
      FOREIGN KEY (stationId) 
      REFERENCES STATIONS (stationId)
      ENABLE VALIDATE);
    
    insert into routeStations values (1,1,3);
    insert into routeStations values (1,3,1);
    insert into routeStations values (1,4,2);
    insert into routeStations values (2,1,1);
    insert into routeStations values (2,4,2);
    commit;
    
    explain plan for select rs.routeID,s.Name
    from ndefontenay.routeStations rs
    join
    ndefontenay.routes r
    on r.routeId=rs.routeId
    join ndefontenay.stations s
    on rs.stationId=s.stationId
    where rs.routeId=1
    order by rs.StationOrder;
    
    set linesize 1000
    set pages 500
    select * from table (dbms_xplan.display);
    
    PLAN_TABLE_OUTPUT
    ----------------------------------------------------------------------------------------------------
    Plan hash value: 2617709240                                                                                                                                                                                                                                                                                 
    
    ---------------------------------------------------------------------------------------------------                                                                                                                                                                                                         
    | Id  | Operation                      | Name             | Rows  | Bytes | Cost (%CPU)| Time     |                                                                                                                                                                                                         
    ---------------------------------------------------------------------------------------------------                                                                                                                                                                                                         
    |   0 | SELECT STATEMENT               |                  |     1 |    79 |     1 (100)| 00:00:01 |                                                                                                                                                                                                         
    |   1 |  SORT ORDER BY                 |                  |     1 |    79 |     1 (100)| 00:00:01 |                                                                                                                                                                                                         
    |   2 |   NESTED LOOPS                 |                  |       |       |            |          |                                                                                                                                                                                                         
    |   3 |    NESTED LOOPS                |                  |     1 |    79 |     0   (0)| 00:00:01 |                                                                                                                                                                                                         
    |   4 |     TABLE ACCESS BY INDEX ROWID| ROUTESTATIONS    |     1 |    39 |     0   (0)| 00:00:01 |                                                                                                                                                                                                         
    |*  5 |      INDEX RANGE SCAN          | ROUTESTATIONS_PK |     1 |       |     0   (0)| 00:00:01 |                                                                                                                                                                                                         
    |*  6 |     INDEX UNIQUE SCAN          | STATIONS_PK      |     1 |       |     0   (0)| 00:00:01 |                                                                                                                                                                                                         
    |   7 |    TABLE ACCESS BY INDEX ROWID | STATIONS         |     1 |    40 |     0   (0)| 00:00:01 |                                                                                                                                                                                                         
    ---------------------------------------------------------------------------------------------------                                                                                                                                                                                                         
    
    Predicate Information (identified by operation id):                                                                                                                                                                                                                                                         
    ---------------------------------------------------                                                                                                                                                                                                                                                         
    
       5 - access("RS"."ROUTEID"=1)                                                                                                                                                                                                                                                                             
       6 - access("RS"."STATIONID"="S"."STATIONID")
    

    Agora a parte divertida, vamos adicionar um nome de coluna à tabela de rotas. Agora há uma coluna que realmente precisamos em "rotas". O CBO usa o índice para encontrar o rowID para a rota 1, então acessa a tabela (tabela de acesso pelo índice rowid) e captura a coluna "routes.name".

    ALTER TABLE ROUTES
     ADD (name  VARCHAR2(50));
    
    update routes set name='Old Town' where routeId=1;
    update routes set name='North County' where routeId=2;
    commit;
    
    explain plan for select r.name as routeName,s.Name as stationName
    from routeStations rs
    join
    routes r
    on r.routeId=rs.routeId
    join stations s
    on rs.stationId=s.stationId
    where rs.routeId=1
    order by rs.StationOrder;
    
    set linesize 500
    set pages 500
    select * from table (dbms_xplan.display);
    
    PLAN_TABLE_OUTPUT                                                                                                                                                                                                                                                                                           
    ---------------------------------------------------------------------------------------------------
    Plan hash value: 3368128430                                                                                                                                                                                                                                                                                 
    
    ----------------------------------------------------------------------------------------------------                                                                                                                                                                                                        
    | Id  | Operation                       | Name             | Rows  | Bytes | Cost (%CPU)| Time     |                                                                                                                                                                                                        
    ----------------------------------------------------------------------------------------------------                                                                                                                                                                                                        
    |   0 | SELECT STATEMENT                |                  |     1 |   119 |     1 (100)| 00:00:01 |                                                                                                                                                                                                        
    |   1 |  SORT ORDER BY                  |                  |     1 |   119 |     1 (100)| 00:00:01 |                                                                                                                                                                                                        
    |   2 |   NESTED LOOPS                  |                  |       |       |            |          |                                                                                                                                                                                                        
    |   3 |    NESTED LOOPS                 |                  |     1 |   119 |     0   (0)| 00:00:01 |                                                                                                                                                                                                        
    |   4 |     NESTED LOOPS                |                  |     1 |    79 |     0   (0)| 00:00:01 |                                                                                                                                                                                                        
    |   5 |      TABLE ACCESS BY INDEX ROWID| ROUTES           |     1 |    40 |     0   (0)| 00:00:01 |                                                                                                                                                                                                        
    |*  6 |       INDEX UNIQUE SCAN         | ROUTES_PK        |     1 |       |     0   (0)| 00:00:01 |                                                                                                                                                                                                        
    |   7 |      TABLE ACCESS BY INDEX ROWID| ROUTESTATIONS    |     1 |    39 |     0   (0)| 00:00:01 |                                                                                                                                                                                                        
    |*  8 |       INDEX RANGE SCAN          | ROUTESTATIONS_PK |     1 |       |     0   (0)| 00:00:01 |                                                                                                                                                                                                        
    |*  9 |     INDEX UNIQUE SCAN           | STATIONS_PK      |     1 |       |     0   (0)| 00:00:01 |                                                                                                                                                                                                        
    |  10 |    TABLE ACCESS BY INDEX ROWID  | STATIONS         |     1 |    40 |     0   (0)| 00:00:01 |                                                                                                                                                                                                        
    ----------------------------------------------------------------------------------------------------                                                                                                                                                                                                        
    
    Predicate Information (identified by operation id):                                                                                                                                                                                                                                                         
    ---------------------------------------------------                                                                                                                                                                                                                                                         
    
       6 - access("R"."ROUTEID"=1)                                                                                                                                                                                                                                                                              
       8 - access("RS"."ROUTEID"=1)                                                                                                                                                                                                                                                                             
       9 - access("RS"."STATIONID"="S"."STATIONID")      
    
    • 21
  2. mustaccio
    2016-03-11T14:31:13+08:002016-03-11T14:31:13+08:00

    Você está certo, não há ordem inerente de registros em uma tabela relacional. Isso significa que você precisa fornecer alguma forma explícita de ordenar as estações dentro de cada rota.

    Dependendo de como você está planejando acessar os dados, você pode

    1. Adicione a sequenceNumbercoluna to RouteStationspara armazenar, obviamente, a sequência de cada estação em cada rota.
    2. Adicione a nextStationIdcoluna para armazenar um "ponteiro" para a próxima estação em cada rota.
    • 4
  3. Josh Simar
    2016-03-16T12:48:04+08:002016-03-16T12:48:04+08:00

    Não vi ninguém afirmar nada sobre isso, então pensei em adicionar para sua nota. Eu também colocaria um índice exclusivo não clusterizado (dependendo do seu RDBMS) na tabela RouteStations/RouteStops em todas as três colunas. Assim você não vai errar e o ônibus vai para as 2 próximas estações. Isso tornará mais difícil para atualizações, mas acho que ainda deve ser considerado como parte de um bom design.

    • 0
  4. Ian Ringrose
    2016-03-12T05:13:49+08:002016-03-12T05:13:49+08:00

    Estou falando como um programador de aplicativos :

    Nem pense em fazer roteamento ou tabela de horários com consultas no banco de dados (ou em um procedimento armazenado), nunca será rápido o suficiente. ( A menos que seja apenas um problema de “lição de casa”. )

    Mesmo para um aplicativo que processa os dados na memória, o carregamento dos dados do banco de dados nunca será rápido, a menos que todos os dados sejam carregados na inicialização ou os dados sejam armazenados de forma desmoralizada. Uma vez que os dados são desmoralizados, há pouco sentido em usar um banco de dados relacional.

    Portanto, pensaria no banco de dados como sendo a cópia “mestre” dos dados e aceitaria que também teria que armazená-lo pré-processado na memória do aplicativo ou em um servidor de caixa como o membase.

    A resposta de ndefontenay fornece um bom design de tabela como ponto de partida, mas você deve considerar que as rotas têm horários diferentes dependendo da hora do dia e geralmente têm paradas diferentes dependendo da hora, dia da semana ou até férias escolares.

    • -1

relate perguntas

  • Os índices filtrados podem ajudar a melhorar as consultas baseadas em uma hora inserida ou isso deve ser evitado?

  • Qual é a diferença entre os tipos de dados MySQL VARCHAR e TEXT?

  • É melhor armazenar os valores calculados ou recalculá-los a pedido? [duplicado]

  • Armazenar vs calcular valores agregados

  • Quais são algumas maneiras de implementar um relacionamento muitos-para-muitos em um data warehouse?

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