使用WHERE“”和“”子句进行SQL查询优化
我试图优化一个长查询,并提高其可读性。 带AND关键字的WHERE子句是否不能正确读取索引或影响读取性能 例如: 表tblTransactions包含61795条记录使用WHERE“”和“”子句进行SQL查询优化,sql,sql-server,query-optimization,where-clause,Sql,Sql Server,Query Optimization,Where Clause,我试图优化一个长查询,并提高其可读性。 带AND关键字的WHERE子句是否不能正确读取索引或影响读取性能 例如: 表tblTransactions包含61795条记录 DECLARE @DateTypeId INT = 1 DECLARE @FromDate DATETIME = '01/01/2000' DECLARE @ToDate DATETIME = '01/01/2019' SELECT * FROM tblTransactions ts WHERE (((ts.Transact
DECLARE @DateTypeId INT = 1
DECLARE @FromDate DATETIME = '01/01/2000'
DECLARE @ToDate DATETIME = '01/01/2019'
SELECT *
FROM tblTransactions ts
WHERE (((ts.TransactionDate BETWEEN @FromDate AND @ToDate) AND @DateTypeId = 1)
OR ((ts.PostingDate BETWEEN @FromDate AND @ToDate) AND @DateTypeId = 2))
执行的总时间为9秒。这是查询的另一个示例
DECLARE @DateTypeId INT = 1
DECLARE @FromDate DATETIME = '01/01/2000'
DECLARE @ToDate DATETIME = '01/01/2019'
IF @DateTypeId = 1
SELECT *
FROM tblTransactions ts
WHERE ts.TransactionDate BETWEEN @FromDate AND @ToDate
ELSE IF @DateTypeId = 2
SELECT *
FROM tblTransactions ts
WHERE ts.PostingDate BETWEEN @FromDate AND @ToDate
此查询的执行时间为8-9秒。就可读性而言,我更喜欢第一个查询,但就性能而言,我更喜欢第二个查询。但是如果查询太长,建议执行哪个查询?请尝试获得更好的性能:
DECLARE @DateTypeId INT = 1
DECLARE @FromDate DATETIME = '01/01/2000'
DECLARE @ToDate DATETIME = '01/01/2019'
IF @DateTypeId = 1
SELECT *
FROM tblTransactions ts
WHERE @FromDate >= ts.TransactionDate <= @ToDate
ELSE IF @DateTypeId = 2
SELECT *
FROM tblTransactions ts
WHERE @FromDate >= ts.PostingDate <= @ToDate
由于独立查询的运行时间与组合查询的运行时间一样长,因此我将继续使用组合查询,即您也喜欢的第一个查询 查询中唯一的条件是日期,在一种情况下是TransactionDate,在另一种情况下是PostingDate。确保在它们上有单独的索引,以便DBMS可以选择在那里查找日期范围:
create index idx_transact_transaction_date on tbltransactions(transactiondate);
create index idx_transact_posting_date on tbltransactions(postingdate);
优化是一项微妙的任务。。这在很大程度上取决于许多科目 了解表结构列、数据、索引、, 了解要执行的查询以及所涉及的select和JOIN和/或函数中的列非常重要 我们还应该讨论一下您的硬件和sql server版本,但这将成为一个非常深入的分析 让我们试着简化一下 如果您的索引对检索所选列没有用处,我不是说筛选行,那么优化器几乎不会使用它们,它将直接对聚集索引进行完整表扫描,您必须至少具有此功能 如果您的选择与问题中的选择一样简单,请从TBLTTransactions中选择*,我们必须考虑表结构 所以,关键是,如果你只选择了几列,你可以建立一个包含这些列的索引,它会被使用,你会非常高兴的 在索引中包含列时,它们不是索引键的一部分,而是用作有效负载数据 问题是包含的列在索引中占用的空间与它们在表中占用的空间一样大。。因此,如果您有数千条具有大列的记录,那么您将为所涉及的数据复制生成巨大的索引 在考虑了所有这些因素之后,您可以建立超级索引,包括所有选定的列。。也许你会发现总的查询执行时间几乎是一样的 花费的大部分时间不是找到要提取的数据,而是要检索的I/O操作并将它们放入输出中 好的,现在有一些建议和选择: 1我将保留IF/ELSE版本,越简单越好 2尝试使用“选择使用您的名称”中包含的列添加索引。。然后运行查询,检查它们是否被使用,以及性能是否有所提高
CREATE NONCLUSTERED INDEX [IX_TRAN_DATE-INCL-COLS]
ON [dbo].[tblTransactions] ([TransactionDate])
INCLUDE ([PostingDate],[Col1],[Col2],[Col3])
CREATE NONCLUSTERED INDEX [IX_POST_DATE-INCL-COLS]
ON [dbo].[tblTransactions] ([PostingDate])
INCLUDE ([TransactionDate],[Col1],[Col2],[Col3])
3您可以尝试混合解决方案、更简单的索引和复杂的查询
CREATE NONCLUSTERED INDEX [IX_TRAN_DATE]
ON [dbo].[tblTransactions] ([TransactionDate])
CREATE NONCLUSTERED INDEX [IX_POST_DATE]
ON [dbo].[tblTransactions] ([PostingDate])
DECLARE @IDX TABLE (ID INT PRIMARY KEY)
IF @DateTypeId = 1 BEGIN
INSERT INTO @IDX
SELECT ts.TransactionID
FROM tblTransactions ts
WHERE ts.TransactionDate BETWEEN @FromDate AND @ToDate
END ELSE IF @DateTypeId = 2 BEGIN
INSERT INTO @IDX
SELECT ts.TransactionID
FROM tblTransactions ts
WHERE ts.PostingDate BETWEEN @FromDate AND @ToDate
END
以上每一项都是要测试的。。也许这没用
我希望了解一点优化的大问题会有帮助。您使用的是哪种dbms?该代码是特定于产品的。还有性能问题。你能把查询计划也张贴出来吗?你有关于TransactionDate和PostingDate的索引吗?请为你正在使用的数据库产品添加标签,看起来像T-SQL/SQL Server。作为一个实验,你可以在查询的末尾添加选项“重新编译”,像那样运行它们并让我们知道结果吗?两者应该是相同的。SQL Server能够基于变量值短路WHERE子句。在运行以下两条语句并粘贴生成的消息后,您能否同时运行这两个查询?设置统计信息IO设置统计信息时间唯一更改的是介于->>=和=之间,这是无效语法-至少对于SQL server是如此。因此,不能用更好的性能要求来推理。