开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 20 天,点击查看活动详情
在优化性能时,开发人员和架构师通常会忽略调整他们的 SQL 查询。了解数据库的工作原理和编写更好的 SQL 查询在提高性能方面发挥着巨大作用 。 高效的 SQL 查询意味着高质量、可扩展的应用程序。
技巧 1:为列选择合适的数据类型
SQL 中的每个表列都有一个关联的数据类型。您可以选择整数、日期、varchars、布尔值、文本等。开发时,选择正确的数据类型很重要。数字应该是数字类型,日期应该是日期等等,这对于索引是极其重要的。
让我们看看下面的例子。
SELECT employeeID, employeeName
FROM employee
WHERE employeeID = 13412;
上面的[查询]获取 ID 为员工的员工 ID 和姓名13412。如果 employeeID 的数据类型是字符串怎么办? 使用索引时您可能会遇到麻烦,因为当它应该是一个简单的扫描时,它会花费很长时间。
技巧 2:表变量和连接
当您有复杂的查询时,例如获取客户的订单以及他们的姓名和订单日期,您需要的不仅仅是一个简单的选择语句。在本例中,我们从客户和订单表中获取数据。这就是[加入]进来的地方。
让我们看一下连接的例子:
SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate
FROM Orders
INNER JOIN Customers ON Orders.CustomerID=Customers.CustomerID;
SQL 提供
inner、full、left outer和right outer类型的联接。
表变量是临时存储数据的局部变量,具有局部变量的所有属性。不要在连接中使用表变量,因为 SQL 将它们视为单行。尽管它们速度很快,但表变量在连接中的表现并不好。
技巧 3:使用条件WHERE从句
条件WHERE子句用于子集化。假设您遇到这样的情况:
-if SEQ_VAR in (1, 2, 3) & diff(DATE_VAR2, DATE_VAR1)≥ 0
— elif SEQ_VAR in (4, 5, 6) & diff(DATE_VAR2, DATE_VAR1) ≥1
— else diff(DATE_VAR2, DATE_VAR1) ≥2
使用条件WHERE子句,它看起来像这样:
SELECT
DAT.ID_VAR,
DAT.SEQ_VAR,
DAT.NUM_VAR,
DATE_VAR1,
DATE_VAR2,
TRUNC(DATE_VAR2) - TRUNC(DATE_VAR1) AS LAG_IN_DATES
FROM
CURRENT_TABLE DAT
WHERE
(TRUNC(DATE_VAR2) - TRUNC(DATE_VAR1)) >= CASE WHEN SEQ_VAR IN (1,2,3) THEN 0 WHEN SEQ_VAR IN (4,5,6) THEN 1 ELSE 2 END
ORDER BY ID_VAR, SEQ_VAR
技巧 4:使用SET NOCOUNT ON
执行INSERT、SELECT、DELETE和UPDATE操作时,请使用SET NOCOUNT ON。SQL 总是为此类操作返回受影响的行数,因此当您有包含大量连接的复杂查询时,它会影响性能。
使用SET NOCOUNT ON,SQL 将不会计算受影响的行并提高性能。
在以下示例中,我们阻止显示有关受影响的行数的消息。
USE AdventureWorks2012;
GO
SET NOCOUNT OFF;
GO
-- Display the count message.
SELECT TOP(5)LastName
FROM Person.Person
WHERE LastName LIKE 'A%';
GO
-- SET NOCOUNT to ON to no longer display the count message.
SET NOCOUNT ON;
GO
SELECT TOP(5) LastName
FROM Person.Person
WHERE LastName LIKE 'A%';
GO
-- Reset SET NOCOUNT to OFF
SET NOCOUNT OFF;
GO
提示 5:避免ORDER BY、GROUP BY和DISTINCT
仅在必要时使用ORDER BY、GROUP BY和。DISTINCTSQL 创建工作表并将数据放在那里。然后它根据查询组织工作表中的数据,然后返回结果。
技巧 6:完全限定数据库对象名称
使用完全限定的数据库对象名称的目的是消除歧义。完全限定的对象名称如下所示:
DATABASE.SCHEMA.OBJECTNAME.
当您有权访问多个数据库、模式和表时,指定要访问的内容就变得很重要。除非您正在使用具有多个用户和模式的大型数据库,否则您不需要这样做,但这是一个很好的做法。
所以不要使用像这样的语句:
SELECT * FROM TableName
你应该使用:
SELECT * FROM dbo.TableName
技巧 7:了解如何完全保护您的代码
数据库存储各种信息,使它们成为主要的攻击目标。常见的攻击包括[SQL 注入] ,用户输入 SQL 语句而不是用户名并检索或修改您的数据库。SQL注入的例子包括:
textuserID = getRequestString("userID");
textSQL = "SELECT * FROM Users WHERE userID = " + textuserID;
假设你有这个,textuserID将从用户那里获取输入。这是它可能出错的原因:
SELECT * FROM Users WHERE userID = 890 OR 1=1;
由于1=1始终为真,它将从 Users 表中获取所有数据。
您可以使用参数化语句、输入验证、清理输入等来保护您的数据库免受 SQL 注入攻击。如何保护您的数据库取决于 DBMS。您需要了解您的 DBMS 及其安全问题,这样您才能编写安全的代码。