首页 > 代码库 > SQL优化

SQL优化

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

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

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

低效率:

SELECT *FROM Customers

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

高效率查询:

SELECT FirstName, LastName, Address, City, State, ZipFROM Customers

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

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

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

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

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


低效率和不准确的:

SELECT DISTINCT FirstName, LastName, StateFROM Customers

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

高效和正确的:

SELECT FirstName, LastName, Address, City, State, ZipFROM Customers

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

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

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

SELECT Customers.CustomerID, Customers.Name, Sales.LastSaleDateFROM Customers, SalesWHERE Customers.CustomerID = Sales.CustomerID

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

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

SELECT Customers.CustomerID, Customers.Name, Sales.LastSaleDateFROM Customers   INNER JOIN Sales   ON Customers.CustomerID = Sales.CustomerID

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

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

4. 使用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.CustomerIDGROUP BY Customers.CustomerID, Customers.NameHAVING 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.CustomerIDWHERE 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.CustomerIDWHERE Sales.LastSaleDate BETWEEN #1/1/2016# AND #12/31/2016#GROUP BY Customers.CustomerID, Customers.NameHAVING Count(Sales.SalesID) > 5

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

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

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

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

SELECT City FROM CustomersWHERE City LIKE ‘%Char%’

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

更高效的查询是:

SELECT City FROM CustomersWHERE City LIKE ‘Char%’

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


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

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

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

SELECT Customers.CustomerID, Customers.Name, Count(Sales.SalesID)FROM Customers  INNER JOIN Sales  ON Customers.CustomerID = Sales.CustomerIDWHERE Sales.LastSaleDate BETWEEN #1/1/2016# AND #12/31/2016#GROUP BY Customers.CustomerID, Customers.NameLIMIT 10

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

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

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

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

  • 查询一个大表 (超过100万记录).

  • 笛卡尔连接 或 交叉连接。

  • 循环语句.

  • SELECT DISTINCT 语句.

  • 嵌套的子查询.

  • 在大段文本字段上模糊查询

  • 跨schema 查询.



来自为知笔记(Wiz)


SQL优化