前言

对于一些原理性文章园中已有大量的文章尤其是关于索引这一块,我也是花费大量时间去学习,对于了解索引原理对于后续理解查询计划和性能调优有很大的帮助,而我们只是一些内容进行概括和总结,这一节我们开始正式步入学习SQL中简单的查询语句,简短的内容,深入的理解。

简单查询语句

所有复杂的语句都是由简单的语句组成基本都是由SELECT、FROM、WHERE、GROUP BY、HAVING、ORDER BY等组成,当然还包括一些谓词等等。比如当我们要查询某表中所有数据时我们会像如下进行。

SELECT * FROM TABLE

到这里是不是查询就是从SELECT开始呢?我们应该从实际生活举例,如我们需要到菜市场买菜,我们想买芹菜,我们应该是到有芹菜的摊位上去买,也就是从哪里去买,到这里我们会发现上述查询数据的顺序应该是先FROM然后是SELECT。在SQL 2012基础教程中列出子句是按照以下顺序进行逻辑处理。

FROMWHEREGROUP BYHAVINGSELECTORDER BY
SELECT empid, YEAR(orderdate) AS orderyear, COUNT(*) AS numbers FROM Sales.OrdersWHERE custid = '71'GROUP BY empid, YEAR(orderdate)HAVING COUNT(*) > 1ORDER BY empid, orderyear
FROM Sales.OrdersWHERE custid = 71GROUP BY empid, YEAR(orderdate)HAVING COUNT(*) > 1SELECT empid, YEAR(orderdate) AS orderyear, COUNT(*) AS numberordersORDER BY empid, orderyear

我们看到过很多文章一直在讲SQL性能问题,比如在查询所有数据时要列出所有列而非SELECT *,所以在本系列中,我也会在适当的去讲性能问题,比如本节要讲的SELECT 1和SELECT *的性能问题。

SELECT 1和SELECT *性能探讨

在数据库中查看执行计划时我们通常会点击【显示估计的执行计划】快捷键是Ctrl+L,这里我们可以看到它已经表明显示的只是估计的执行计划,所以是不准确的,所以为了显示实际的执行计划,我们应该启动【包括实际的执行计划】,快捷键是Ctrl+M,这样才能得到比较准确的执行计划,如下

查询方式一(整表查询)

USE TSQL2012GOIF EXISTS(SELECT 1FROM Sales.Orders)SELECT 'SELECT 1'GOIF EXISTS(SELECT *FROM Sales.Orders)SELECT 'SELECT *'GO

查询方式二(在索引列上条件查找)

我们对某一列创建索引

CREATE INDEX ix_shipnameON Sales.Orders(shipname)

此时显示查询计划依然一样。我们再来看看其他查询方式。

查询方式三(使用聚合函数)

USE TSQL2012GOIF (SELECT 1FROM Sales.OrdersWHERE shipname = 'Ship to 85-B') = 1SELECT 'SELECT 1'GOIF (SELECT COUNT(*)FROM Sales.OrdersWHERE shipname = 'Ship to 85-B') = 1SELECT 'SELECT *'GO

查询方式四(使用聚合函数Count在非索引列上查找)

USE TSQL2012GOIF (SELECT COUNT(1)FROM Sales.OrdersWHERE freight = '41.3400') = 1SELECT 'SELECT 1'GOIF (SELECT COUNT(*)FROM Sales.OrdersWHERE freight = '41.3400') = 1SELECT 'SELECT *'GO

查询方式五(子查询)

我们看看在子查询中二者性能如何

USE TSQL2012SELECT custid, companyname FROM Sales.Customers AS CWHERE country = N'USA' ANDEXISTS (SELECT * FROM Sales.Orders AS O WHERE O.custid = C.custid)GOSELECT custid, companyname FROM Sales.Customers AS CWHERE country = N'USA' ANDEXISTS (SELECT 1 FROM Sales.Orders AS O WHERE O.custid = C.custid)

查询方式六(在视图中查询)

我们创建视图继续来比较SELECT 1和SELECT *的性能

USE TSQL2012GoCREATE VIEW SaleOdersViewASSELECT shipaddress,shipname,(SELECT unitprice FROM Sales.OrderDetails AS sod where sod.orderid = so.orderid) as tc3FROM Sales.Orders AS soGO
USE TSQL2012SELECT 1 FROM dbo.SaleOdersViewgoSELECT * FROM dbo.SaleOdersViewgo

此时我们通过上述图发现利用视图查询时,SELECT *的性能是如此低下占有97%,而SELECT 1才3%,这是为何呢?不明白其中原因,希望有清楚其中原因的园友能够留下你们的评论给出合理的解释。

SELECT 所有列和SELECT *性能探讨

一直以来所有教程都在讲SELECT *性能比SELECT 所有列性能低,同时也给出了合理的理由,我也一直这样认为,但是在查资料学习过程中,发现如下一段话。

I don't think there is any difference, as long as the SELECT 1/* is inside EXISTS, which really doesn't return any rows – it just returns boolean as soon as condition of the WHERE is checked.I'm quite sure that the SQL Server Query Optimizer is smart enough not to search for the unneeded meta data in the case of EXISTS.I agree that in all the other situations SELECT * shouldn't be used for the reasons Simon mentioned. Also, index usage wouldn't be optimal etc.For me EXISTS (SELECT * ..) is the only place where I allow myself to write SELECT * in production code ;)

总结

通过以上对SELECT 1和SELECT *性能的探讨,在视图中利用SELECT *性能更加低下,同时也结合SELECT *尽量避免用,我是不是可以下结论我可以更倾向于用SELECT 1呢?第二点是看到上述所给的资料SELECT *在Exist中的性能是不是和一定SELECT 所有列一样呢?这是我存在疑问的两个问题,是不是我所疑问的两个问题,没有具体的答案,需要看应用场景呢?那应用场景又是在哪里?毕竟不是专业的DBA,同时对SQL也研究不深,所以希望看到此文的读者,能给出精彩的回答,同时也让我学习学习。

更多相关文章

  1. SQL Server之JSON 函数详解
  2. MySQL系列多表连接查询92及99语法示例详解教程
  3. Android(安卓)- Manifest 文件 详解
  4. Android的Handler机制详解3_Looper.looper()不会卡死主线程
  5. Selector、shape详解(一)
  6. Android(安卓)-- Android(安卓)JUint 与 Sqlite
  7. android 当系统存在多个Launcher时,如何设置开机自动进入默认的La
  8. android2.2资源文件详解4--menu文件夹下的菜单定义
  9. Android发送短信方法实例详解

随机推荐

  1. 基于MVC5中的Model层开发数据注解_实用技
  2. 代码详解AVL树的插入
  3. 厌倦写代码的人是如何做软件开发的
  4. 用户管理和权限和设置——mysql
  5. asp.net core封装layui组件的示例详解
  6. UWP中设置控件样式四种方法
  7. C#中关于DBNULL的解释
  8. ASP.NET Core中用户登录验证实现最低配置
  9. 有关ASP.NET中Config文件的读写讲解
  10. C#中foreach与yield的实例详解