我有person
表如下:
person
表:
id | 第一名称 | 姓氏 | 年龄 |
---|---|---|---|
1 | 约翰 | 史密斯 | 23 |
2 | 大卫 | 棕色 | 18 |
⋮ | ⋮ | ⋮ | ⋮ |
这里的问题与其说是数据库服务器的问题,不如说是网络通信的问题。通过一次选择所有列,您告诉服务器一次返回给您,所有列至于对IO的担忧,@Karamba在评论中给出的问答很好地解决了这些问题:select*vs select column。但对于大多数现实世界中的应用程序(我在各种意义上都使用"应用程序"(,主要关注的只是网络流量以及串行化、传输和反序列化数据所需的时间。尽管事实上,无论哪种方式,答案都是一样的。
因此,如果您打算全部使用所有列,那么收回所有列是很好的,但这可能会带来大量额外的数据传输,特别是如果您在列中存储(例如(长字符串。当然,在许多情况下,这种差异是无法检测到的,而且大多只是原则问题。不是全部,但绝大多数。
这实际上只是你前面提到的懒惰(相信我,我们都有这种感觉(和性能的重要性之间的权衡
也就是说,如果确实打算使用所有列值,那么最好一次将它们全部取回来,然后再提交一堆查询。
把它想象成网络搜索:你进行搜索,找到你的页面,你只需要一个细节。你可以阅读整页,了解关于这个主题的一切,也可以直接跳到你想要做什么的部分。如果这就是你想要的,后者会快得多,但如果你必须了解其他方面,你最好第一次阅读它们,而不是再次搜索并找到网站来谈论它。
如果您不确定将来是否需要其他列值,那么这是您作为开发人员的决定,在这种情况下更有可能。
这完全取决于您的应用程序是什么,数据是什么,您如何使用它,以及性能对您的重要性。
选择单列会对某些查询的性能产生很大影响。例如,查询引擎处理索引比在原始数据页中查找数据更高效。如果覆盖索引可用,即包含查询所需的所有列的索引,那么查询将运行得更快。对于对于可用内存来说太大的大表,使用覆盖索引可能是一个巨大的胜利。(在某些情况下,性能可以提高几个数量级。(
当列的数量有限时,另一种情况是当一个或多个列非常大时,例如BLOB或TEXT列。它们的大小可以增长到数万字节甚至兆字节。检索它们并给服务器带来很大的负载。
如果您已经准备好了语句并且表的底层结构发生了更改,那么使用*
是有危险的。查询本身可能会过时(我在其他数据库上也遇到过这个问题,但在MySQL上没有遇到(。潜在的更改可以像更改列的名称一样简单。相反,被捕获为编译时错误的是一个可能更神秘的运行时错误。
一般来说,避免*
的原因更多地与网络性能有关。在许多情况下,这不会有多大区别。如果您从一个表中返回20行,其中每行平均包含100或200个字节,那么在大多数硬件环境中,选择所有列和列的子集之间的差异将很小。用于查询的绝大多数时间将用于编译查询、在引擎中执行查询以及读取数据页。返回200字节和2000字节之间的区别可能不会太大。
然而,在某些情况下(例如上面列出的情况(,它可以产生很大的影响。因此,避免*
是一个好习惯,但偶尔使用它可能不会降低你的系统。
至少在PostgreSQL中,选择一列的性能要快于所有列的性能。
在PostgreSQL中,我创建了test
表,其中10个id_x
列和1000万行如下所示:
CREATE TABLE test AS SELECT generate_series(1, 10000000) AS id_1,
generate_series(1, 10000000) AS id_2,
generate_series(1, 10000000) AS id_3,
generate_series(1, 10000000) AS id_4,
generate_series(1, 10000000) AS id_5,
generate_series(1, 10000000) AS id_6,
generate_series(1, 10000000) AS id_7,
generate_series(1, 10000000) AS id_8,
generate_series(1, 10000000) AS id_9,
generate_series(1, 10000000) AS id_10;
然后,我在下面交替运行了2个查询,总共运行了6次*每个查询总共运行3次:
SELECT * FROM test;
SELECT id_1 FROM test;
<结果>
SELECT * FROM test; | SELECT id_1 FROM test; | |
---|---|---|
第一次运行 | 13.817秒 | 2.634秒 |
第二次运行 | 13.579秒 | 2.606秒 |
第三次运行 | 1.341秒 | 2.611秒 |
平均 | 13.579秒 | 2.617秒 |