8 个用于生产环境的 SQL 查询优化调整

SUM服务器监控软件监控的SQL Server性能主要涉及到会话数、连接数、死锁数、锁、数据库性能(日志空间、表空间等核心)、缓存等核心性能。SUM可监控SQL Server 7.0、SQL Server 2000、SQL Server 2005、SQL Server 2008等各个版本。

8个用于生产环境的SQL查询优化调整

1. 首先分析业务需求

在前面的一篇文章中, 我们讨论了针对BI的业务分析最佳实践best practices to define business requirements for BI)。这些做法可以应用在优化SQL查询中,如:

  • 识别利益相关方. 确保所有涉及方都参与了讨论开发查询语句。在查询生产数据库时,要确保DBA团队在场。
  • 专注于业务目标. 确保查询有一个明确的和唯一的目的。在生产数据库中实验或重复报告是一个不必要的风险。
  • 制定良好需求讨论框架。确定报告的功能和范围,确定其预期的受众。 这将有助于关注表上查询细节的正确性。
  • 通过有效的提问来沟通需求 这些问题通常遵循5 WS– Who? What? Where? When? Why?
  • 写非常具体的要求,并利益相关者确认 生产数据库的性能是非常重要的,所以不能有不清楚或不明确的需求。确保需求是尽可能的具体,确保在运行查询语句前需求是经过确认的。

2. 定义select的字段,来代替select * 操作

当运行SELECT语句时,很多数据库开发人员会使用SELECT * (选择全部列)的缩写来选择表中所有需要的数据,但是,如果一张表中有很多字段,同时表数据量较大有许多条数据,由于查询了许多非必要数据,将会浪费数据库资源.

SELECT语句中定义查询字段,数据库将只查询符合业务需要的数据,让我们看看下面的例子:业务只需要客户的邮寄地址.

低效率:

SELECT *

FROM Customers

这个查询将获得顾客表中除了邮寄地址以外的许多数据,比如电话号码,活跃日期(上次登录日期),销售备注和顾客服务说明.

高效率查询:

SELECT FirstName, LastName, Address, City, State, Zip

FROM Customers

这个查询只会选出邮件地址需要的信息.

为了维护所有表和字段名称的索引,对系统表中运行一条查询语句即可.系统表比如 INFORMATION_SCHEMA 或者 ALL_TAB_COLUMNS (对于 MS SQL Server数据库请查阅以下:链接)

:MYSQL中运行SELECT * FROM INFORMATION_SCHEMA.COLUMNS 即可查询出数据库中所有的表和视图以及其结构;

3. Select中列出更多的列去避免使用SELECT DISTINCT语句

SELECT DISTINCT 是一个查询中较为方便的移除重复列的方法,但是SELECT DISTINCT 底层采用了对所有指明唯一的列进行分组以实现得到不重复的数据结果,为了完成这一目标,需要非常大量的运算.此外,数据分组的结果可能并不精确.为了避免使用SELECT DISTINCT,使用选择更多的列的方式来创造每条数据唯一的结果集比较恰当.

低效率和不准确的:

SELECT DISTINCT FirstName, LastName, State

FROM Customers

这个查询不能查询出在同一个州具有相同姓名的多个人。受欢迎的名字,如:David Smith 或者 Diane Johnson,将组合在一起,导致记录数不准确。 在更大的数据库,大量的类似 David SmithDiane Johnson的记录会导致查询很慢。

高效和正确的:

SELECT FirstName, LastName, Address, City, State, Zip

FROM Customers

通过添加更多的字段,而不使用SELECT DISTINCT 来返回非重复记录。数据库不必对任何字段进行分组,返回的记录数也是正确的。 

4. 使用INNER JOIN 而不是WHERE来创建连接

一些SQL开发人员更喜欢使用WHERE来做join,比如:

SELECT Customers.CustomerID, Customers.Name, Sales.LastSaleDate

FROM Customers, Sales

WHERE Customers.CustomerID = Sales.CustomerID

这个类型join实际上创建时笛卡尔连接,也被称为笛卡尔积或 CROSS JOIN 在笛卡尔连接中,所有可能的组合都会被创建出来。在上面的例子中,如果有1000顾客和1000条销售记录,这个查询会先产生1000000个结果,然后通过正确的 CustomerID过滤出1000条记录。 这是一种低效利用数据库资源,数据库多做100倍的工作。 在大型数据库中,笛卡尔连接是一个大问题,对两个大表的笛卡尔积会创建数10亿或万亿的记录。

为了避免创建笛卡尔积,应该使用INNER JOIN 

SELECT Customers.CustomerID, Customers.Name, Sales.LastSaleDate

FROM Customers

   INNER JOIN Sales

   ON Customers.CustomerID = Sales.CustomerID

 

这样数据库就只产生等于CustomerID 1000条目标结果。

有些数据库系统会识别出 WHERE连接并自动转换为 INNER JOIN。在这些数据库系统中,WHERE 连接与INNER JOIN 就没有性能差异。但是, INNER JOIN 是所有数据库都能识别的,因此DBA会建议在你的环境中使用它。

5. 使用WHERE而不是使用 HAVING 来筛选

类似于上面提到的概念, 高效查询的目的就是只从数据库得到需要的记录。 每一个SQL 指令,HAVING 语句是放在WHERE 语句后面来运算的。 如果想基于条件来过滤记录,无疑WHERE 会更佳高效。

例如, 我们假定在2016年有200销售记录,我们想查询出2016年的客户销售数。

SELECT Customers.CustomerID, Customers.Name, Count(Sales.SalesID)

FROM Customers

   INNER JOIN Sales

   ON Customers.CustomerID = Sales.CustomerID

GROUP BY Customers.CustomerID, Customers.Name

HAVING Sales.LastSaleDate BETWEEN #1/1/2016# AND #12/31/2016#

这个查询会从销售表中拉取1000条记录,然后过滤得到2016年的200条记录,最后才是对这个数据集计数。

相比而言, WHERE 就直接限制了拉取的数据记录数:

SELECT Customers.CustomerID, Customers.Name, Count(Sales.SalesID)

FROM Customers

  INNER JOIN Sales

  ON Customers.CustomerID = Sales.CustomerID

WHERE Sales.LastSaleDate BETWEEN #1/1/2016# AND #12/31/2016#

GROUP BY Customers.CustomerID, Customers.Name

本查询只拉取2016年的200条记录,然后对这个数据集计数。这样就不必使用 HAVING 

HAVING 只能应用在聚合字段上。在上面的查询中,我们可以添加一个显示消费记录大于5的客户的条件。

SELECT Customers.CustomerID, Customers.Name, Count(Sales.SalesID)

FROM Customers

   INNER JOIN Sales

   ON Customers.CustomerID = Sales.CustomerID

WHERE Sales.LastSaleDate BETWEEN #1/1/2016# AND #12/31/2016#

GROUP BY Customers.CustomerID, Customers.Name

HAVING Count(Sales.SalesID) > 5

6. 仅在模糊查询的尾部使用通配符

当搜索文本数据时,如 城市或姓名,通配符可以扩大搜索范围。但是,模糊搜索却是一个低效的搜索。

在使用通配符的查询中,特别是匹配到结尾处的通配符,数据库会在选中的字段中匹配所有的记录。

考虑如下查询,查询城市名以 ‘Char’开头的:

SELECT City FROM Customers

WHERE City LIKE ‘%Char%’

这个查询会包含我们所期望的这些数据: Charleston, Charlotte Charlton 但是,它也会返回这些不需要的数据:Cape Charles, Crab OrchardRichardson.

更高效的查询是:

SELECT City FROM Customers

WHERE City LIKE ‘Char%’

这个查询就仅返回所期望的结果:Charleston, Charlotte Charlton

7. 使用LIMIT来限制查询结果集

在第一次运行查询前,通过使用 LIMIT来确保结果是可获取的和有意义的。 (某些数据库中,是使用TOP) LIMIT 语句会仅返回指定数量的数据。在编辑查或细化查询语句时使用 LIMIT可以防止对生成数据库产生大数据查询。

在上面的2016年销售查询中,可以如下语句来限制返回10条记录:

SELECT Customers.CustomerID, Customers.Name, Count(Sales.SalesID)

FROM Customers

  INNER JOIN Sales

  ON Customers.CustomerID = Sales.CustomerID

WHERE Sales.LastSaleDate BETWEEN #1/1/2016# AND #12/31/2016#

GROUP BY Customers.CustomerID, Customers.Name

LIMIT 10

通过这样的简单查询,我们可以看到是否有可用的数据集。

8. 在非高峰时段运行分析统计查询

为了最小化查询对生成数据库的影响,应该告诉DBA在非高峰时段调度执行查询。查询应该在并发用户数最少的时段运行,比如:典型的时间段是半夜时段(凌晨3-5点)。

符合以下情况越多,就越应该选择在晚上运行查询:

  • 查询一个大表 (超过100万记录).
  • 笛卡尔连接  交叉连接。
  • 循环语句.
  • SELECT DISTINCT 语句.
  • 嵌套的子查询.
  • 在大段文本字段上模糊查询
  • schema 查询.

 

业务热线电话:(+86)021-52765253 021-61172807      上海哲涛网络科技有限公司版权所有 © 2005-2018       沪ICP备06058430-1号

沪公网安备 31011302000898号

校睿宝,培训机构学员管理软件,教师工资计算软件,消课管理软件!

手机智慧课堂答题,短信答题,微信答题!

数据备份软件,文件数据备份软件,文件备份软件,B/S架构备份软件,分布式计算机备份软件!