我做了一些研究,发现我应该将路线存储为一系列停靠点。就像是:
Start -> Stop A -> Stop B -> Stop C -> End
Run Code Online (Sandbox Code Playgroud)
我创建了三个表:
...其中RouteStops是一个连接表。
我有类似的东西:
+---------+
| routeId |
+---------+
| 1 |
+---------+
| 2 |
+---------+
Run Code Online (Sandbox Code Playgroud)
+-----------+------+
| stationId | Name |
+-----------+------+
| 1 | A |
+-----------+------+
| 2 | B |
+-----------+------+
| 3 | C |
+-----------+------+
| 4 | D |
+-----------+------+
Run Code Online (Sandbox Code Playgroud)
+-------------+---------------+
| routeId(fk) | stationId(fk) |
+-------------+---------------+
| 1 | A |
+-------------+---------------+
| 1 | C |
+-------------+---------------+
| 1 | D |
+-------------+---------------+
| 2 | A |
+-------------+---------------+
| 2 | D |
+-------------+---------------+
Run Code Online (Sandbox Code Playgroud)
1号路经过
Station A -> Station C -> Station D
Run Code Online (Sandbox Code Playgroud)
2号路经过
Station A -> Station D
Run Code Online (Sandbox Code Playgroud)
这是存储路线的好方法吗?
根据维基百科:
[...] 除非
ORDER BY
指定了子句,否则数据库系统不保证行的任何排序[...]
我可以依赖这样的数据库模式还是应该以不同的方式完成?
这实际上是我的大学项目,所以我只是想知道这种模式是否可以被认为是正确的。对于这种情况,我可能只存储多条路线(约 3-5 个)和车站(约 10-15 个),每条路线将包含约 5 个车站。我也很高兴听到在真正的大型巴士公司的情况下这应该是什么样子。
Nic*_*nay 21
对于所有导致数据库架构的业务分析,我建议编写规则:
您注意到的第 1 条和第 2 条规则暗示了多对多关系,因此您正确地得出结论来创建 routeStation。
第三条规则很有趣。这意味着需要额外的列来满足要求。它应该去哪里?我们可以看到这个属性依赖于Route AND Station。因此它应该位于 routeStation 中。
我会在表 routeStations 中添加一个名为“stationOrder”的列。
+-------------+---------------+---------------
| routeId(fk) | stationId(fk) | StationOrder |
+-------------+---------------+---------------
| 1 | 1 | 3 |
+-------------+---------------+---------------
| 1 | 3 | 1 |
+-------------+---------------+---------------
| 1 | 4 | 2 |
+-------------+---------------+---------------
| 2 | 1 | 1 |
+-------------+---------------+---------------
| 2 | 4 | 2 |
+-------------+---------------+---------------
Run Code Online (Sandbox Code Playgroud)
然后查询变得容易:
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 |
+-------------+---------------+
Run Code Online (Sandbox Code Playgroud)
笔记:
为了在注释 3 上进行开发,我构建了用例:
这是 Oracle 12c 企业版。
请注意,在下面的执行计划中,根本没有使用表路由。Cost Base Optimizer (CBO) 知道它可以直接从 routeStations 的主键中获取 routeId(步骤 5,ROUTESTATIONS_PK 上的 INDEX RANGE SCAN,谓词信息 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")
Run Code Online (Sandbox Code Playgroud)
现在是有趣的部分,让我们向路由表添加一个列名。现在在“路线”中有一个我们实际上需要的列。CBO 使用索引查找路由 1 的 rowID,然后访问表(通过索引 rowid 访问表)并抓取“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")
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
7673 次 |
最近记录: |