SELECT * 测试

描述

大家通常禁止在生产环境直接使用select * 已成常识了,也常常在开发规范中就会规定不允许直接使用select *,那么我们为什么不允许使用select * ,在一些什么场景下select * 会出问题?能否控制不能直接使用select *?出于这些疑问,我们特别测试记录一下。

 

测试环境

Microsoft SQL Server 2012 - 11.0.2100.60 (X64) 
Feb 10 2012 19:39:15 
Copyright (c) Microsoft Corporation
Enterprise Edition (64-bit) on Windows NT 6.2 <X64> (Build 9200: )
 

select * 可能会造成业务功能出错

假设我们有一个视图 V_test 代码如下:
1 CREATE VIEW v_test
2 AS
3     SELECT  *
4     FROM    test

 

你在web前端调用直接使用如下脚本并对应好显示的字段,当时功能是正常的。
   SELECT  *
    FROM    v_test

 

test 表结构如下:

 

后来因为业务调整,有人调整了test表 ,并加一个字段F ,那么接下来的后果就会前端相应的功能因新增的字段F直接报错。
 

select * 可能会造成性能方面的问题

测试数据准备
 1 --新建测试表
 2 IF OBJECT_ID('test', 'U') IS NOT NULL
 3     DROP TABLE test;
 4 CREATE TABLE test
 5     (
 6       id int IDENTITY(1, 1) ,
 7       a nvarchar(20) ,
 8       b nvarchar(15) ,
 9       c nvarchar(20) ,
10       d int ,
11       e float
12     );
 1 --造测试数据
 2 DECLARE @i INT; 
 3 SET @i = 10000;
 4 WHILE ( @i > 0 )
 5     BEGIN 
 6         INSERT  INTO test
 7                 ( a ,
 8                   b ,
 9                   c ,
10                   d ,
11                   e
12                 )
13                 SELECT  RAND() * 1000 ,
14                         RAND() * 1000 ,
15                         REPLICATE('a', 3) ,
16                         @i ,
17                         @i - 1;
18         SELECT  @i = @i - 1;
19     END; 
1 --新建索引(主键、非聚集索引)
2 ALTER TABLE dbo.test ADD CONSTRAINT PK_test_id PRIMARY KEY(ID);
3 CREATE INDEX IX_test_1 ON dbo.test(a);

 

查询条件使用主键字段的执行计划,主键是默认覆盖全部字段。

 

如直接使用字段a做查询条件

 

还是聚集索引扫描,全表扫,无法使用我们已新建好的非聚集索引IX_test_1,在上述语句中因该索引未覆盖到非a 的字段。假设实际场景我们只需取a字段,那么执行计划又是怎么样的?

 

如上图,就会走我们期望的索引,同时也可以减少因select * 而多读的字段(id、b、c、d、e)的网络传输,所以,尽量指定自己所需的字段名,可以避免一些无谓的性能开销。
 

如何控制不让 select *

假设我们不允许在上述测试表test上执行select * 可以如何处理
 1 --新建测试表
 2 IF OBJECT_ID('test', 'U') IS NOT NULL
 3     DROP TABLE test;
 4 CREATE TABLE test
 5     (
 6       id int IDENTITY(1, 1) ,
 7       a nvarchar(20) ,
 8       b nvarchar(15) ,
 9       c nvarchar(20) ,
10       d int ,
11       e float,
12       abort_select_all  AS  (1/0)        ---新增控制字段
13     );
14 --造测试数据
15 DECLARE @i INT; 
16 SET @i = 10000;
17 WHILE ( @i > 0 )
18     BEGIN 
19         INSERT  INTO test
20                 ( a ,
21                   b ,
22                   c ,
23                   d ,
24                   e
25                 )
26                 SELECT  RAND() * 1000 ,
27                         RAND() * 1000 ,
28                         REPLICATE('a', 3) ,
29                         @i ,
30                         @i - 1;
31         SELECT  @i = @i - 1;
32     END; 
33 --新建索引 (主键、非聚集索引)
34 ALTER TABLE dbo.test ADD CONSTRAINT PK_test_id PRIMARY KEY(ID);
35 CREATE INDEX IX_test_1 ON dbo.test(a);

 

如下图,如果select *  因读取了abort_select_all字段(1/0)就会直接报错,从而达到不能直接select *的效果;

 

直接按字段名查询没有问题(非abort_select_all字段)。
非select *
直接按字段名查询没有问题。

 
posted @ 2017-05-21 21:32  jil.wen  阅读(847)  评论(0编辑  收藏  举报