概念性问题:单个查询的速度是否比联接更快?或者:我是否应该尝试将客户端上想要的每个信息都压缩到一个 SELECT语句中,或者仅使用看起来方便的数量?
TL; DR:如果我加入的查询花费的时间比运行单个查询所花费的时间更长,这是我的错还是应该这样?
首先,我不是非常了解数据库,所以可能只是我一个人,但是我注意到当我必须从多个表中获取信息时,通过对单个表进行多次查询来获取此信息“通常”更快(也许包含一个简单的内部联接)并在客户端将数据修补在一起,以尝试编写一个(复杂的)联接查询,在此我可以在一个查询中获得所有数据。
我试图将一个非常简单的示例放在一起:
模式设置:
CREATE TABLE MASTER
( ID INT NOT NULL
, NAME VARCHAR2(42 CHAR) NOT NULL
, CONSTRAINT PK_MASTER PRIMARY KEY (ID)
);
CREATE TABLE DATA
( ID INT NOT NULL
, MASTER_ID INT NOT NULL
, VALUE NUMBER
, CONSTRAINT PK_DATA PRIMARY KEY (ID)
, CONSTRAINT FK_DATA_MASTER FOREIGN KEY (MASTER_ID) REFERENCES MASTER (ID)
);
INSERT INTO MASTER values (1, 'One');
INSERT INTO MASTER values (2, 'Two');
INSERT INTO MASTER values (3, 'Three');
CREATE SEQUENCE SEQ_DATA_ID;
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.5);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.7);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 2, 2.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.14);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.7);
查询A:
select NAME from MASTER
where ID = 1
结果:
| NAME |
--------
| One |
查询B:
select ID, VALUE from DATA
where MASTER_ID = 1
结果:
| ID | VALUE |
--------------
| 1 | 1.3 |
| 2 | 1.5 |
| 3 | 1.7 |
查询C:
select M.NAME, D.ID, D.VALUE
from MASTER M INNER JOIN DATA D ON M.ID=D.MASTER_ID
where M.ID = 1
结果:
| NAME | ID | VALUE |
---------------------
| One | 1 | 1.3 |
| One | 2 | 1.5 |
| One | 3 | 1.7 |
当然,我没有衡量这些性能,但是可以观察到:
- 查询A + B返回与查询C相同数量的可用信息。
- A + B必须向客户端返回1 + 2x3 == 7个“数据单元”
- C必须将3x3 == 9“数据单元”返回给客户端,因为使用联接,我自然会在结果集中包括一些冗余。
从此概括(按实际情况):
与接收相同信息量的单个查询相比,联接的查询总是必须返回更多的数据。由于数据库必须将数据拼凑在一起,因此对于大型数据集,可以假设数据库在单个联接的查询上必须比在单个查询上做更多的工作,因为(至少)它必须将更多的数据返回给客户端。
会因此得出结论,当我观察到将客户端查询拆分为多个查询会产生更好的性能时,这只是解决之道,还是意味着我搞砸了合并的查询?