而那个ActiveRecord Query Interface,默认生成的SQL可是select *啊,开发的时候的确不碍事,但总不能就这样发布了,还得把所有用到的column名字都补回去,下次改到这里再注释掉。要不就不用ActiveRecord Query Interface。
现在,还有谁敢拿着里面还有select *的代码去发布啊,现在都找不到多少PHP代码里面到处都是select *了吧。
先说说优点:
一、打字少!看看下面对比,哪个简单就不用说了,更少的输入意味着更少的错误:
select * from bugs;
和
select bug_id, date_reported, summary, description, resolution, reported_by,assigned_to, verified_by, status, priority, hours,......, from bugs;
二、在添加和修改或删除的时候不需要更改查询语句。
上面这两点都满足了程序员“懒”的习惯。所以大家都非常喜欢使用。
下面谈谈缺点:
说到这里一定会有同学跳出说:这有性能问题,不能这么用! 的确,在在查询中使用通配符会影响性能,一次查询过多(有时候不需要的列也会被查到)会增加客户端和数据库之间的网络传输开销。
why AR's default SELECT *
is not a big deal
一、性能问题永远不是应该最先考虑的问题。 很少应用的数据会达到百万、千万级别。在开发阶段代码简单灵活可扩展永远是第一位的。
二、考虑到两种特殊情况,一个表字段非常多或是有大字段(text/blob 类型)。这种情况最彻底的解决方案是垂直拆分表和剥离大字段。
比如 users 这样的表很大,将 users 表分成 accounts + user_blog_parts + user_ask_parts + user_topic_parts 等。
带有大字段的表 topics 分成 topics 和 topic_texts。
三、不使用通配符会带来更多的 Query Cache Miss 和额外的缓存存储开销。无论是数据库级别的 Query Cache 还是 ActiveRecord 级别的 Query Cache。原因很简单 Query Cache 使用 sql 语句作为缓存 key,会把 select *
和 select colum1,column2
当作不同的查询。
mysql> select * from users order by id limit 1;
mysql> SHOW STATUS LIKE '%Qcache%';
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 16690672 |
| Qcache_hits | 3 |
| Qcache_inserts | 6 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 70 |
| Qcache_queries_in_cache | 6 |
| Qcache_total_blocks | 16 |
+-------------------------+----------+
8 rows in set (0.00 sec)
mysql> select id,nick_name,email from users order by id limit 1;
1 row in set (0.00 sec)
mysql> SHOW STATUS LIKE '%Qcache%';
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 16689648 |
| Qcache_hits | 3 |
| Qcache_inserts | 7 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 70 |
| Qcache_queries_in_cache | 7 |
| Qcache_total_blocks | 18 |
+-------------------------+----------+
8 rows in set (0.00 sec)
mysql>
四、和 Query Cache 类似,如果项目用了类似 CacheMoney 这样的行缓存插件,通配符方式会带来额外的性能提升,有些查询甚至不需要去 hit db,比指定列的方式省的那一点儿流量强的多。
五、有些查询使用select *
不能进行覆盖索引优化。但是别忘了 AR 是可以使用 select 选项的... 默认 select * ,在特殊的地方手动指定查询列,这有什么问题呢?这就是 CoC 啊..
结论:
所以,单从一条查询来看某些做法可能是最好的,但是从整体的角度看未必是最优的。 有些同学干了很多脏活累活儿,看起来很勤劳勇敢的样子,但是也未必起到什么效果:-)