一、减少输入
程序员都喜欢使用通配符,如:
SELECT * FROM Person
又或者省略字段名:
INSERT INTO Person VALUES('10','张飞'...)
二、捷径会让你迷失方向
对于以上代码,如果你仅仅是在开发过程中用于查看一下数据库信息,又或者你只是写个小程序自己玩玩,这是没有什么问题的。
但是如果一旦你习惯于这样编写正式生产环境中的代码,那问题就随之而来了。
1、破坏代码重构
如果数据库更改了,比如增加了一列:
ALTER TABLE Person Add Age int
这下糟糕了,你程序中所有的
INSERT INTO Person VALUES(...)
语句都会报错。
早使用这种隐式模式执行INSERT时,输入必须严格按照定义表时的那些列的顺序,如果列变了,这条语句就会抛出一个错误,甚至有可能就会抛出一个错误,甚至有可能把数据写到错误的列里面去。
假设原本是使用隐式模式查询:
SELECT * FROM Person
但是加入删掉了中间的一个列:
ALTER TABLE Person DROP COLUMN Age
那么加入是使用DataTable的方式装载数据库内容,那么row[10]可能就已经不是第十个。在重命名、添加、删除列的时候,程序代码并不能适应查询结果的改变。如果使用了通配符,就无法预测这个查询会返回多少行。
2、隐藏的开销
在查询中使用通配符可能会影响性能和扩展性。一次性查询所获取的列越多,客户端程序和数据库之间的网络传输的字节也越多。
生产环境中的程序可能会有很多并发的查询请求。它们都共享同一个网络带宽。太多客户端同时查询返回上千条记录可能会造成阻塞。
3、合理使用反模式
在你只是为了快速地写几个脚本对一个解决方案进行测试,或者写临时SQL查询对当前数据进行查看时,使用通配符是合情合理的。只执行一两次的查询对可维护性没有任何要求。
当然,输入一张很多列的表的所有列名是很耗时的,对某些人来说,开发效率可能比程序运行效率更加重要。例如,当你开发的是较少用户量的小公司内部访问程序,这时候返回数据所使用的带宽比查询语句本身要多得多。这时候没必要纠结这些问题。
三、解决方案-明确列出列名
1、预防错误
每次查询都列出所有你需要用到的列,而不是使用通配符或者隐式列的列表。
SELECT Id,Name... FROM Person
INSERT INTO Person (Id,Name,Age...) VALUES(1,'张飞',22...)
这样做的好处如下:
- 如果这张表的某一列的位置被移动过,他不会对返回结果中这一列的位置造成影响。
- 如果这张表中新加入一列,它是不会出现在查询结果中的。
- 如果从这张表中删除一列,你的查询会得到一个错误,但是直接就能够找到问题所在,这是符合尽早出错原则的。
2、减少资源占用
如果必须关心软件的可扩展性和程序的吞吐量,你应该检查一下网络传输过程中可能造成的浪费。一旦在SQL中禁用通配符,那么就很自然地去除那些不需要的列,提高了带宽和内存的使用效率。