Otobüs güzergahlarını bir veritabanında saklama


16

Biraz araştırma yaptım ve bir güzergahı bir durak dizisi olarak saklamam gerektiğini buldum. Gibi bir şey:

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

Üç tablo oluşturdum:

  • Rotalar
  • Duraklar
  • RouteStops

... burada RouteStops bir bağlantı tablosu.

Benim gibi bir şey var:

Rotalar

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

İstasyonlar

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

Güzergah 1 geçer

Station A -> Station C -> Station D

Güzergah 2 geçer

Station A -> Station D

Bu rotaları depolamanın iyi bir yolu mu?

Wikipedia'ya göre :

[...] veritabanı sistemi, bir ORDER BYcümle belirtilmedikçe satırların herhangi bir şekilde sıralanmasını garanti etmez [...]

Böyle bir veritabanı şemasına güvenebilir miyim, yoksa bu farklı bir şekilde yapılmalıdır?

Bu aslında benim üniversite projem, bu yüzden böyle bir şemanın doğru olarak kabul edilip edilemeyeceğini merak ediyorum. Bu durumda, muhtemelen sadece birkaç rota (yaklaşık 3-5) ve istasyon (yaklaşık 10-15) kaydederim, her rota yaklaşık 5 istasyondan oluşur. Ayrıca, gerçek ve büyük otobüs şirketi durumunda bunun nasıl görünmesi gerektiğini duymaktan memnuniyet duyarım.


Genel Transit Feed Spesifikasyonu'na bakmak isteyebilirsiniz ; GTFS özet akışlarının CSV dosyaları olarak değiştirileceği belirtilirken, uygulamalar genellikle GTFS'yi ilişkisel bir veritabanında depolar ve işler.
Kurt Raschke

3
Sorunuz 'Durdur' ve 'İstasyon' terimleri arasında geçiş yapıyor. Muhtemelen alan adı kelime dağarcığınızı açıklığa kavuşturmalısınız ( yani bir ad seçin ve onunla kalın).
Tersosauros

@ monoh_.i de benzer bir sorunuz var dba.stackexchange.com/questions/194223/…. eğer bir fikriniz varsa paylaşabilirsiniz
vizyon

Yanıtlar:


19

Veritabanı mimarisine yol açan tüm iş analizleri için kural yazmanızı öneririm:

  • Bir rotada 2 veya daha fazla istasyon var
  • Bir İstasyon birçok güzergah tarafından kullanılabilir
  • Bir rotadaki istasyonlar belirli bir sırada gelir

Fark ettiğiniz gibi 1. ve 2. kurallar çoktan çoğa bir ilişki anlamına gelir, böylece routeStation'ları doğru bir şekilde sonuçlandırdınız.

3. kural ilginç olanıdır. İhtiyaca uyması için fazladan bir sütuna ihtiyaç olduğu anlamına gelir. Nereye gitmeli? Bu tesisin Rota VE İstasyon'a bağlı olduğunu görebiliriz. Bu nedenle routeStation'larda bulunmalıdır.

Tablo stationStation "stationOrder" adlı bir sütun eklemek istiyorum.

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

Sonra sorgulama kolaylaşır:

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

Notlar:

  1. Benim örneğimde StationId RouteStations sabit. İstasyonAdı kimliği olarak kullanıyorsunuz.
  2. Bir rota adı kullanmıyorsanız, bunu routeStations'tan alabileceğiniz için routeId'e bile ihtiyaç yoktur.
  3. Rota tablosuna bağlansanız bile, veritabanı optimize ediciniz bu ekstra bağlantıya ihtiyaç duymadığını fark eder ve sadece ekstra adımları kaldırır.

Not 3 üzerinde geliştirmek için, kullanım senaryosunu oluşturdum:

Bu Oracle 12c Enterprise.

Aşağıdaki yürütme planında bu tablo yollarının hiç kullanılmadığını unutmayın. Maliyet Tabanı Optimize Edici (CBO), routeId'yi doğrudan routeStations'ın birincil anahtarından alabileceğini biliyor (5. adım, ROUTESTATIONS_PK üzerindeki INDEX RANGE SCAN, Tahmin Bilgileri 5 - erişim ("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")

Şimdi eğlenceli kısım, rota tablosuna bir sütun adı ekleyelim. Şimdi "rotalarda" ihtiyacımız olan bir sütun var. CBO, dizin 1 için satır kimliğini bulmak için dizini kullanır, sonra tabloya erişir (dizin satır kimliği ile tablo erişimi) ve "route.name" sütununu alır.

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")      

@ Nicolas.i de benzer bir soru var bana yardımcı olabilir misiniz dba.stackexchange.com/questions/194223/…
vizyon

3

Haklısınız, ilişkisel bir tabloda doğal bir kayıt sırası yoktur. Bu, her rotadaki istasyonları sipariş etmenin açık bir yolunu sağlamanız gerektiği anlamına gelir.

Verilere nasıl erişmeyi planladığınıza bağlı olarak

  1. Açıkçası, her bir istasyondaki her bir istasyonun sırasını saklamak için sequenceNumbersütunu ekleyin RouteStations.
  2. nextStationIdHer rotadaki bir sonraki istasyona bir "işaretçi" kaydetmek için sütunu ekleyin .

@ mustaccio.i de benzer bir soru var bana yardımcı olabilir misiniz dba.stackexchange.com/questions/194223/…
vizyon

0

Kimsenin bunun hakkında bir şey ifade etmediğini gördüm, bu yüzden notunuza ekleyeceğimi düşündüm. Ayrıca üç sütun boyunca RouteStations / RouteStops tablosuna kümelenmemiş bir Benzersiz dizin (RDBMS'nize bağlı olarak) yerleştiririm. Bu şekilde hata yapamaz ve otobüsün sonraki 2 istasyona gitmesini sağlayamazsınız. Bu, güncellemeler için zorlaştıracak, ancak yine de iyi bir tasarımın parçası olarak düşünülmelidir.


-1

Bir uygulama programcısı olarak konuşuyorum :

Veritabanına (veya depolanmış bir proc) sorgularla yönlendirme veya zaman çizelgesi yapmayı bile düşünmeyin, bu asla yeterince hızlı olmayacaktır. ( Bu sadece bir “ödev” sorunu olmadığı sürece. )

Bellekteki verileri işleyen bir uygulama için bile, tüm veriler başlangıçta yüklenmedikçe veya veriler demoralize edilmiş bir formda saklanmadığı sürece veritabanından veri asla hızlı olmaz. Veriler demoralize edildikten sonra ilişkisel veritabanı kullanmanın pek bir anlamı yoktur.

Bu nedenle veritabanını verinin “ana” kopyası olarak düşünür ve ayrıca önceden işlenmiş uygulama belleğinde veya membase gibi bir para çekme sunucusunda saklamak zorunda kalacağımı kabul ederim.

ndefontenay'ın cevabı başlangıç ​​noktası olarak iyi bir masa tasarımı verir, ancak rotaların günün saatine bağlı olarak farklı zamanlamalara sahip olduğunu ve zamana, haftanın gününe ve hatta okul tatillerine bağlı olarak genellikle farklı duraklara sahip olduğunu düşünmeniz gerekir.


5
Hiçbir yerde yönlendirme veya zaman çizelgesi yapmak istediğini söylemiyor; bir DB'de rotaların nasıl saklanacağını sorar . Ayrıca, bir programcı demoralize edilebilir olsa da, eminim ki veriler bir noktada normalleştirilecektir . :)
AnoE
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.