搜索
首页数据库mysql教程T-SQL动态查询(1)简介_MySQL

 

起因:


由于最近工作需要及过去一直的疑问,所以决定着手研究一下动态SQL。由于离开一线开发有点年头了,很多技巧性的东西没有过多研究,作为DBA和《SQL Server性能优化与管理的艺术》一书的独立作者,更多的是关注在满足功能要求前提下的性能问题。但是我认为本文不仅对DBA有用,对数据库开发人员甚至设计师、架构师等都有一定的参考价值。

 

前言:


读者是否遇到过类似功能:一个应用程序(不管是B/S还是C/S结构),有某个/些功能,允许用户选择不同的条件来进行查询(为了简便期间,这里仅针对查询功能)。极端情况下,用户可以通过界面选择结果集的不同的展示列、列展示顺序、排序形式甚至二次查询等。这些功能使用前端编程语言实现未尝不可,有时候甚至更佳,但是前端实现毕竟需要后台数据库的支持,所以这里更加集中在数据库层面。

上面的例子中,用户看到的可能就是这样,但是作为一个开发人员,你需要考虑的东西就不仅仅是这些了,假设我们使用存储过程来实现这个功能的数据支持,那么你需要考虑的是:不同的查询条件可能需要关联不同的表,比如需要同时筛选日期和货号,这两个条件是分布在A、B两表,那么你在查询时就要进行关联。但是当用户选择筛选货号和客户名时,这些数据可能分布在B、C两表,那么你需要在同一个存储过程中进行B、C表的关联。

由于关系数据库理论的限制,你很难做到灵活构建这种逻辑的同时保持代码的简洁及高效。除了用游标加大量判断这种几乎能实现任何功能但又往往极其低效的方式之外,动态SQL就出现在我们的考虑范围里面。我们需要借助某些工具来实现两个目的:得到正确数据和获得合理的性能。

简介:


在现代信息系统中,上面的例子广泛存在。但是随之引发的一个核心问题是:在SQL Server(估计在所有RDBMS中均是),没有一个单一的执行计划可以很好地支持所有的可能的查询条件。同时你也希望SQL Server针对用户的输入进行优化。

通常在数据库层面实现这种要求的方式有两种:

1. 编写带有查询提示(如OPTION(RECOMPILE))的静态SQL,强制SQL Server每次都对查询进行编译。

2. 使用动态SQL 创建一个可以覆盖用户定义的查询条件的字符串并执行语句。

这两种方式都有适用常见,各有优缺点,不能简单地说哪个好哪个不好,本系列文章将介绍两类的相关内容。

注意:本系列将使用SQL 2008 R2并用微软示例数据库AdventureWorks2008 R2作为演示。

基础知识:

为了让读者有一些知识准备,本问先介绍一些基础知识,这些基础知识有:

执行计划执行计划缓存统计信息参数嗅探(简介)

注:为了控制文章的篇幅,本系列文章不打算深入探讨上面的知识,更详细的信息可查阅本人书籍《SQL Server性能优化与管理的艺术》中相关信息。

执行计划:

当一个SQL语句(SQL语句/批 或存储过程)提交给SQL Server之后,SQL Server会先分析语句的语法,若不符合要求马上停止后续操作并返回错误信息给客户端。

当SQL语句语法分析通过之后,SQLServer会根据语句的文本在内存的计划缓存中(Plan Cache,属于内存的Buffer Pool一部分)查找是否有可用的执行计划,若有,则直接执行,若无,则进行编译阶段。编译后生成执行计划提交给存储引擎进行执行并缓存。大概流程如下:

\

 

执行计划是性能的核心之一,存储引擎根据执行计划访问和返回数据给客户端,好的执行计划能高效、快速地完成数据请求,而不合理的执行计划会使一个本来很简单的请求的运行时间从几秒上升到数小时。而且执行计划也是分析性能问题的核心工具。在SQL Server Management Studio(SQL 2000叫查询分析器,SQL2005开始简称SSMS),查看执行计划可以通过快捷键:Ctrl+M(实际执行计划)和Ctrl+L(预估执行计划)来获取,也可以通过图形化界面中的下图来获取:

\

 

执行计划缓存:

在SQL Server优化器对语句进行编译和优化之后,提交给存储引擎执行,随即把执行计划缓存到内存的Plan Cache中以便后续重用。

计划缓存的最重要的目的是为了减少不必要的编译和重编译,这两个操作在负载很大的系统中会带来明显的CPU压力。如果在一个一秒钟某个存储过程会被调用超百次的系统中,避免一个只需要5ms的编译过程,可以使存储过程的执行计划从5分钟降到100ms。

另外计划缓存与语句的文本有密切关系,后续会介绍,对于下面两个语句,他们的执行计划是可以被重用的:

 

SELECT ID,A,B FROM TB WHERE ID=1
SELECT ID,A,B FROM TB WHERE ID=10

 

但是下面两个语句会被认为两个不同的语句,导致第二个语句被认为新语句而进行编译,通常会导致性能问题和资源浪费:

 

SELECT ID,A,BFROM TB WHERE ID=1
SELECT ID,A,B FROM     TB WHERE ID=10  --注意空格


 

对于这类问题,通常的解决方案是合理的编码规范和使用参数化查询,后续将介绍。

另外,计划缓存有先进先存的特性,假设下面一个存储过程:

 

CREATEPROC TEST (@ID INT)
AS
  SELECT ID,A,B FROM TB WHERE ID=@ID
GO

同时假设表TB上ID列的数据分布极其不均匀,比如ID=1的数据在列上占了90%,而ID=10的数据在列上只有0.01%,数据行超百万,并且有合适的索引支持。在这种情况下,针对ID=1的查询,合理的应该是进行索引扫描,而对于ID=10的查询,合理的应该是索引查找。当第一次运行存储过程并以@ID=1为参数时,执行计划按索引扫描的方式产生并缓存,这是对的。但是当第二次执行是以@ID=10为参数时,可能因为某些原因执行计划被重用,依旧使用索引扫描方式,此时你可能会明显感觉到性能降低。这种情况反之亦然。关于这个情况在后续会整理一个关于参数嗅探的系列文章中详述。

最后,计划缓存是在内存中,也就是说,它是不稳定的,重启服务/服务器或某些命令和操作都可能导致计划被刷出内存。如有必要可以定期收集并存储在专门的监控数据库中或把执行计划另存为文件。

 

统计信息:


统计信息是一个描述表数据的“表”,简单来说就是描述数据的数据。我们常说的数据分布,对于SQL Server来说,就是存储在统计信息中。统计信息可以是自动创建或者手动创建的,并且通常在索引创建时就会附带创建对应的统计信息。关于统计信息的详述可见《SQL Server性能优化与管理的艺术》第六章。

统计信息也是性能优化的核心,SQLServer在分析语句语法之后,会根据统计信息的内容,选择执行计划中使用什么索引及表关联的算法,统计信息的过时和不准确会严重影响执行计划生成和服务器的整体性能。

同时,在优化过程中,如果统计信息足够准确,优化器可以通过判断数据是否有需要关联从而避免不必要的表关联。系列文章的后续部分也会做演示。

提醒:现行统计信息的算法最晚从SQL2000开始沿用至今,但是从SQL 2014开始做了大改动,算法更加合理,所以如有条件,建议使用SQL 2014或后续版本。

 

参数嗅探:


很多地方把这个功能视为性能杀手或者一个贬义词,但是存在即合理,我们应该具体情况具体分析。那么参数嗅探是什么呢?在执行计划缓存部分已经介绍了那个例子。在一些存储过程或者其他对象中,使用了传参数的方式,但是SQL Server并不知道你在实际执行时会传入什么参数,此时SQL Server就会使用一个预估值用于生成执行计划,但是在某些情况下,SQL Server也会“嗅探”实际传入的参数,并判断缓存中的执行计划针对当前语句及其参数是否不合理,是否有必要进行重编译。

所以这种功能其实是必要的,并且很多情况是有用的。但是如果因为某些原因,在本来不需要使用的时候使用了这个功能,会导致原来很合理的执行计划被抛弃,选择不合理的执行计划,其结果就是查询运行好好的,但是突然变得奇慢无比。

总的来说,需要了解参数嗅探的本质,才能下定论。后续会专门写一个关于参数嗅探的文章,一旦发布会在本文中加入链接。

 

环境准备:


软件环境:SQL Server 2008 R2,最好企业版。操作系统随意。

示例数据库:AdventureWorks 2008 R2,下载地址:http://msftdbprodsamples.codeplex.com/releases/view/59211

 

除了上面环境,还要在数据库中构建一个存储过程的模版,说是模版,其实就是后续演示过程中,在这个模版里面添加某些语句而已:

 

CREATE PROCEDURE sp_Get_orders
                 @salesorderid     int     = NULL,
                 @fromdate    datetime     = NULL,
                 @todate      datetime     = NULL,
                 @minprice    money        = NULL,
                 @maxprice    money        = NULL,
                 @custid      nchar(5)     = NULL,
                 @custname    nvarchar(40) = NULL,
                 @prodid      int          = NULL,
                 @prodname    nvarchar(40) = NULL,
                 @employeestrvarchar(MAX) = NULL,
                 @employeetblintlist_tbltype READONLYAS
 
SELECT o.SalesOrderID, o.OrderDate, od.UnitPrice, od.OrderQty,
       c.CustomerID, per.FirstName as CustomerName,p.ProductID,
       p.Name as ProductName,  per.BusinessEntityID as EmpolyeeID
FROM   Sales.SalesOrderHeader o
INNER JOIN   Sales.SalesOrderDetail od ON o.SalesOrderID = od.SalesOrderID
INNER JOIN   Sales.Customer c ON o.CustomerID = c.CustomerID
INNER JOIN   Person.Person per on c.PersonID=per.BusinessEntityID
INNER JOIN   Production.Product p ON p.ProductID = od.ProductID
WHERE  ???
ORDER  BY o.SalesOrderID
GO


 

注意上面WHERE ???的意思是后续例子中将会通过增减这个 WHERE条件并创建新命名的存储过程来演示。

简要说明一下存储过程的参数:

 

@salesorderid 订单ID
@fromdate 起始日期
@todate 结束日期
@minprice 最低价
@maxprice 最高价
@custid 客户ID
@custname 客户名
@prodid 产品ID
@prodname 产品名
@employeestr 雇员ID的字符串组合,以逗号分割
@employeetbl 雇员ID的表值参数

 


 

 

如果用户不使用任何查询条件,那么查询条件将不起筛选作用,因此需要一个单纯的EXEC SP_GET_ORDERS的方式返回所有数据库订单的功能。

通过对存储过程的改写,可以应对业务中的下面需求:

 

用户可以选择如何对结果排序。依赖于输入的参数,语句可以访问不同的表或列。用户可以选择比较操作符,如@custname=’xxxx’或@custname !=’xxxx’。用户可以从输出结果中添加或移除列,也可以在聚合查询中选择聚合什么。其他你能想到甚至你不能想到但客户会想到的需求。

下一篇文章:T-SQL动态查询(2)——关键字查询

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
MySQL与Sqlite有何不同?MySQL与Sqlite有何不同?Apr 24, 2025 am 12:12 AM

MySQL和SQLite的主要区别在于设计理念和使用场景:1.MySQL适用于大型应用和企业级解决方案,支持高性能和高并发;2.SQLite适合移动应用和桌面软件,轻量级且易于嵌入。

MySQL中的索引是什么?它们如何提高性能?MySQL中的索引是什么?它们如何提高性能?Apr 24, 2025 am 12:09 AM

MySQL中的索引是数据库表中一列或多列的有序结构,用于加速数据检索。1)索引通过减少扫描数据量提升查询速度。2)B-Tree索引利用平衡树结构,适合范围查询和排序。3)创建索引使用CREATEINDEX语句,如CREATEINDEXidx_customer_idONorders(customer_id)。4)复合索引可优化多列查询,如CREATEINDEXidx_customer_orderONorders(customer_id,order_date)。5)使用EXPLAIN分析查询计划,避

说明如何使用MySQL中的交易来确保数据一致性。说明如何使用MySQL中的交易来确保数据一致性。Apr 24, 2025 am 12:09 AM

在MySQL中使用事务可以确保数据一致性。1)通过STARTTRANSACTION开始事务,执行SQL操作后用COMMIT提交或ROLLBACK回滚。2)使用SAVEPOINT可以设置保存点,允许部分回滚。3)性能优化建议包括缩短事务时间、避免大规模查询和合理使用隔离级别。

在哪些情况下,您可以选择PostgreSQL而不是MySQL?在哪些情况下,您可以选择PostgreSQL而不是MySQL?Apr 24, 2025 am 12:07 AM

选择PostgreSQL而非MySQL的场景包括:1)需要复杂查询和高级SQL功能,2)要求严格的数据完整性和ACID遵从性,3)需要高级空间功能,4)处理大数据集时需要高性能。PostgreSQL在这些方面表现出色,适合需要复杂数据处理和高数据完整性的项目。

如何保护MySQL数据库?如何保护MySQL数据库?Apr 24, 2025 am 12:04 AM

MySQL数据库的安全可以通过以下措施实现:1.用户权限管理:通过CREATEUSER和GRANT命令严格控制访问权限。2.加密传输:配置SSL/TLS确保数据传输安全。3.数据库备份和恢复:使用mysqldump或mysqlpump定期备份数据。4.高级安全策略:使用防火墙限制访问,并启用审计日志记录操作。5.性能优化与最佳实践:通过索引和查询优化以及定期维护兼顾安全和性能。

您可以使用哪些工具来监视MySQL性能?您可以使用哪些工具来监视MySQL性能?Apr 23, 2025 am 12:21 AM

如何有效监控MySQL性能?使用mysqladmin、SHOWGLOBALSTATUS、PerconaMonitoringandManagement(PMM)和MySQLEnterpriseMonitor等工具。1.使用mysqladmin查看连接数。2.用SHOWGLOBALSTATUS查看查询数。3.PMM提供详细性能数据和图形化界面。4.MySQLEnterpriseMonitor提供丰富的监控功能和报警机制。

MySQL与SQL Server有何不同?MySQL与SQL Server有何不同?Apr 23, 2025 am 12:20 AM

MySQL和SQLServer的区别在于:1)MySQL是开源的,适用于Web和嵌入式系统,2)SQLServer是微软的商业产品,适用于企业级应用。两者在存储引擎、性能优化和应用场景上有显着差异,选择时需考虑项目规模和未来扩展性。

在哪些情况下,您可以选择SQL Server而不是MySQL?在哪些情况下,您可以选择SQL Server而不是MySQL?Apr 23, 2025 am 12:20 AM

在需要高可用性、高级安全性和良好集成性的企业级应用场景下,应选择SQLServer而不是MySQL。1)SQLServer提供企业级功能,如高可用性和高级安全性。2)它与微软生态系统如VisualStudio和PowerBI紧密集成。3)SQLServer在性能优化方面表现出色,支持内存优化表和列存储索引。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境