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 Smith、Diane 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 Orchard和Richardson.
更高效的查询是:
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 查询.
转自:https://coyee.com/article/11077-8-ways-to-fine-tune-your-sql-queries-for-production-databases
8 个用于生产环境的 SQL 查询优化调整的更多相关文章
- 基于redis的分布式锁(不适合用于生产环境)
基于redis的分布式锁 1 介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分 ...
- mysql_secure_installation 安全安装(用于生产环境设置)
编译安装完mysql5.6,如果用于生产环境,最好执行mysql_secure_installation来做一些常规化安全设置. 需要提前将~mysql/bin加入环境变量 /apps/mysql// ...
- 结合Git实现Mysql差异备份,可用于生产环境
埋头苦干多年一直没写过文章,今天突发狂想,为LNMP阵营贡献一些力量.就从平时工作过程中的心得和一些技巧分享出来.今天就猿们最熟悉的Mysql开始宅鸟的开篇博客文章.欢迎猿们拍砖.转载. 注意:宅鸟的 ...
- Ocelot中文文档-Raft(实验功能不能用于生产环境)
Ocelot最近整合了Rafty,这是我在去年一直研究的Raft的一个实现. 这个项目实验性非常强,所以在我认为它没问题之前,请不要在生产环境中使用Ocelot的这个功能. Raft是一种分布式一致性 ...
- Jexus 5.8.2 正式发布为Asp.Net Core进入生产环境提供平台支持
Jexus 是一款运行于 Linux 平台,以支持 ASP.NET.PHP 为特色的集高安全性和高性能为一体的 WEB 服务器和反向代理服务器.最新版 5.8.2 已经发布,有如下更新: 1,现在大 ...
- (转) 将ASP.NET Core应用程序部署至生产环境中(CentOS7)
原文链接: http://www.cnblogs.com/ants/p/5732337.html 阅读目录 环境说明 准备你的ASP.NET Core应用程序 安装CentOS7 安装.NET Cor ...
- CentOs7 +Jexus 5.8.2部署Asp.Net Core WebApi 1.0生产环境
Jexus 是一款运行于 Linux 平台,以支持 ASP.NET.PHP 为特色的集高安全性和高性能为一体的 WEB 服务器和反向代理服务器.最新版 5.8.2 已经发布,有如下更新: 1,现在大 ...
- 将ASP.NET Core应用程序部署至生产环境中(CentOS7)
这段时间在使用Rabbit RPC重构公司的一套系统(微信相关),而最近相关检验(逻辑测试.压力测试)已经完成,接近部署至线上生产环境从而捣鼓了ASP.NET Core应用程序在CentOS上的部署方 ...
- 将ASP.NET Core应用程序部署至生产环境中(CentOS7)(转)
阅读目录 环境说明 准备你的ASP.NET Core应用程序 安装CentOS7 安装.NET Core SDK for CentOS7. 部署ASP.NET Core应用程序 配置Nginx 配置守 ...
随机推荐
- 【转】Unity3d:读取FBX中的动画
从模型中获得切割好的动画clip,并且对其中设置好的动画事件进行修改方法: 1.动画模型后缀为.FBX.在Unity3d中,能够显示FBX中的动画.要加载模型中的AnimationClip,只要Ass ...
- vue 项目搭建
vue init webpack-simple 工程名字<工程名字不能用中文> 简单部署 vue init webpack 工程名字<工程名字不能用中文> 完整部署
- 使用jquery修改表单的提交地址
基本思路: 通过使用jquery选择器得到对应表单的jquery对象,然后使用attr方法修改对应的action 示例程序一: 默认情况下,该表单会提交到page_one.html 点击button之 ...
- 525. Contiguous Array两位求和为1的对数
[抄题]: Given a binary array, find the maximum length of a contiguous subarray with equal number of 0 ...
- 75-扩展GCD-时间复杂度
扩展gcd-时间复杂性 题目内容: 计算循环语句的执行频次 for(i=A; i!=B ; i+=C) x+=1; 其中A,B,C,i都是k位无符号整数. 输入描述 A B C k, 其中0<k ...
- p4364 [九省联考2018]IIIDX
传送门 分析 我们先考虑如果所有数都不相同我们应该怎么办 我们可以直接贪心的在每个点放可行的最大权值 但是题目要求可以有相同的数 我们可以考虑每次让当前节点可发且尽量大的同时给兄弟节点留的数尽量大 我 ...
- extends注意事项
属性可以在子类中被调用,而局部变量不可以
- 一张图让你看懂HDMI针脚定义
一张图让你看懂HDMI针脚定义 摘自:http://www.hdmiaoc.com/cjwt-175.html 什么是HDMI线,HDMI插头的每根PIN脚是什么意思? 大部分使用HDMI标准的研发及 ...
- C#事件订阅及触发例子
最典型的事件例子,猫叫了(事件源),老鼠跑了(事件订阅者),惊醒主人(事件订阅者) 源代码: class Program { static void Main(string[] args) { Cat ...
- 用kettle实现数据库迁移之oracle到mysql
项目完成后,需要把历史oracle 的数据库转移mysql 用kettle 转换数据. 步骤: 1.打开spoon.bat,文件-->新建-->转换,点击“主对象树”,DB连接右键“新建” ...

