在没有数据仓库或单独的分析数据库的组织中,报告的唯一来源和最新的数据可能是在现场生产数据库中。 在查询生产数据库时,优化是关键。一个低效的查询可能会对生产数据库产生大量的资源消耗,如果查询有错误会引发性能下降 或服务不可用。因此优化查询使得对数据库性能影响最小化是非常重要的。

第 1 段(可获 1.04 积分)

1. 首先分析业务需求

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

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

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

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

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

低效率:

SELECT *
FROM Customers
第 3 段(可获 1.11 积分)

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

高效率查询:

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,使用选择更多的列的方式来创造每条数据唯一的结果集比较恰当.

第 4 段(可获 1.84 积分)

低效率和不准确的:

SELECT DISTINCT FirstName, LastName, State
FROM Customers

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

高效和正确的:

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

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

第 5 段(可获 1.16 积分)

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亿或万亿的记录。

第 6 段(可获 1.59 积分)

为了避免创建笛卡尔积,应该使用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会建议在你的环境中使用它。

第 7 段(可获 1.03 积分)

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#
第 8 段(可获 1.11 积分)

这个查询会从销售表中拉取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 。

第 9 段(可获 0.91 积分)

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. 仅在模糊查询的尾部使用通配符

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

第 10 段(可获 0.81 积分)

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

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

SELECT City FROM Customers
WHERE City LIKE ‘%Char%’

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

更高效的查询是:

SELECT City FROM Customers
WHERE City LIKE ‘Char%’

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

第 11 段(可获 1.05 积分)

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 查询.

转自:https://coyee.com/article/11077-8-ways-to-fine-tune-your-sql-queries-for-production-databases

8 个用于生产环境的 SQL 查询优化调整的更多相关文章

  1. 基于redis的分布式锁(不适合用于生产环境)

    基于redis的分布式锁 1 介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分 ...

  2. mysql_secure_installation 安全安装(用于生产环境设置)

    编译安装完mysql5.6,如果用于生产环境,最好执行mysql_secure_installation来做一些常规化安全设置. 需要提前将~mysql/bin加入环境变量 /apps/mysql// ...

  3. 结合Git实现Mysql差异备份,可用于生产环境

    埋头苦干多年一直没写过文章,今天突发狂想,为LNMP阵营贡献一些力量.就从平时工作过程中的心得和一些技巧分享出来.今天就猿们最熟悉的Mysql开始宅鸟的开篇博客文章.欢迎猿们拍砖.转载. 注意:宅鸟的 ...

  4. Ocelot中文文档-Raft(实验功能不能用于生产环境)

    Ocelot最近整合了Rafty,这是我在去年一直研究的Raft的一个实现. 这个项目实验性非常强,所以在我认为它没问题之前,请不要在生产环境中使用Ocelot的这个功能. Raft是一种分布式一致性 ...

  5. Jexus 5.8.2 正式发布为Asp.Net Core进入生产环境提供平台支持

    Jexus 是一款运行于 Linux 平台,以支持  ASP.NET.PHP 为特色的集高安全性和高性能为一体的 WEB 服务器和反向代理服务器.最新版 5.8.2 已经发布,有如下更新: 1,现在大 ...

  6. (转) 将ASP.NET Core应用程序部署至生产环境中(CentOS7)

    原文链接: http://www.cnblogs.com/ants/p/5732337.html 阅读目录 环境说明 准备你的ASP.NET Core应用程序 安装CentOS7 安装.NET Cor ...

  7. CentOs7 +Jexus 5.8.2部署Asp.Net Core WebApi 1.0生产环境

    Jexus 是一款运行于 Linux 平台,以支持  ASP.NET.PHP 为特色的集高安全性和高性能为一体的 WEB 服务器和反向代理服务器.最新版 5.8.2 已经发布,有如下更新: 1,现在大 ...

  8. 将ASP.NET Core应用程序部署至生产环境中(CentOS7)

    这段时间在使用Rabbit RPC重构公司的一套系统(微信相关),而最近相关检验(逻辑测试.压力测试)已经完成,接近部署至线上生产环境从而捣鼓了ASP.NET Core应用程序在CentOS上的部署方 ...

  9. 将ASP.NET Core应用程序部署至生产环境中(CentOS7)(转)

    阅读目录 环境说明 准备你的ASP.NET Core应用程序 安装CentOS7 安装.NET Core SDK for CentOS7. 部署ASP.NET Core应用程序 配置Nginx 配置守 ...

随机推荐

  1. python算法之选择排序

    选择排序 选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理如下.首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大 ...

  2. VS2017更新后 在WIN7上找不到 stdio.h等的问题

    项目->属性->配置属性->常规->windows SDK版本.将其换成你现在的版本即可解决问题,如果不行就重新下个最新版SDK,如WIN10的.

  3. 混合开发之iOS快速集成DSBridge

    DSBridge-IOS github:https://github.com/wendux/DSBridge-IOS 使用 Native 实现API 代理类 //JsApiTest.m @implem ...

  4. spring4-2-bean配置-4-bean之间的关系

  5. 9-queue

    在C++中只要#include<queue>即可使用队列类,其中在面试或笔试中常用的成员函数如下(按照最常用到不常用的顺序) 1. push 2. pop 3. size 4. empty ...

  6. SpringBoot 集成Mybatis时 使用通用插件Mapper 注意事项

    1.如果在SpringBoot的启动入口类上面加入注解 @MapperScan(basePackages = "com.leecx.mapper")      使用的是   org ...

  7. 前端学习--HTML标签温习一

    1.<a>标签 在所有浏览器中,链接的默认外观如下: 1)未被访问的链接带有下划线而且是蓝色的 2)已被访问的链接带有下划线而且是紫色的 3)活动链接带有下划线而且是红色的 提示:如果没有 ...

  8. 事务(进程 ID 64)与另一个进程被死锁在 锁 资源上,并且已被选作死锁牺牲品。

    访问频率比较高的app接口,在后台写的异常日志会偶尔出现以下错误. 事务(进程 ID 64)与另一个进程被死锁在 锁 资源上,并且已被选作死锁牺牲品.请重新运行该事务 实所有的死锁最深层的原因就是一个 ...

  9. Spring MVC 小计

    前端控制器是DispatcherServlet 应用控制器     1 处理器映射器(Handler Mapping)   进行处理器管理 2 视图解析器(View Resolver)         ...

  10. 手把手教你看KEGG通路图!

    手把手教你看KEGG通路图! 亲爱的小伙伴们,是不是正关注代谢通路研究?或者你正面对数据,绞尽脑汁?小编当然不能让亲们这么辛苦,今天就跟大家分享KEGG代谢通路图的正确解读方法,还在迷糊中的小伙伴赶紧 ...