首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带有“WHERE”和“”子句的SQL查询优化

带有“WHERE”和“”子句的SQL查询优化
EN

Stack Overflow用户
提问于 2018-04-10 08:36:36
回答 3查看 94关注 0票数 0

我试图优化一个长查询,并提高它的可读性。带和关键字的WHERE子句是否没有正确读取索引或影响读取的性能?

示例:表tblTransactions包含61,795条记录

代码语言:javascript
复制
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秒。这是查询的另一个示例。

代码语言:javascript
复制
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秒。就可读性而言,我更喜欢第一个查询,但就性能而言,我更喜欢第二个查询。但是,如果查询太长,建议执行的查询是哪一个?

EN

回答 3

Stack Overflow用户

发布于 2018-04-10 11:51:28

优化是一项微妙的任务。这在很大程度上取决于学科的能力。

了解表结构(列、数据、索引)非常重要,重要的是知道要执行的查询(选择和联接中的列和/或所涉及的函数)。

我们也应该讨论一下您的硬件和sql-server版本,但是它将成为一个非常深入的分析。

让我们试着简化一下。

如果索引对于检索所选列没有用处(我不是说过滤行),优化器将(几乎)不使用它们,并且它将直接对聚集索引进行完整的表扫描(至少必须具有此功能)。

如果您的选择与您的问题(select * from tblTransactions)一样简单,我们必须考虑表结构。

因此,重点是,如果您只选择了几个列,您就可以构建一个包含这些列的索引,并且它将被使用,并且您会非常高兴(确定?)。

当索引中包含列时,它们不是索引键的一部分,而是用作有效负载数据。

问题是,包含列,在索引中占用的空间与表中的空间一样大。因此,如果您有数千条包含大列的记录,您将为所涉及的数据复制生成巨大的索引。

在考虑了所有这些之后,您可以建立超级索引,其中包括所有选定的列。也许您可以发现,总的查询执行时间几乎是相同的。

所花费的大部分时间不是找出要提取的数据,而是查找要检索的I/O操作,并将它们放在输出中。

好的,现在有一些建议和选择:

1)我将保留IF/ELSE版本,越简单越好。

2)尝试添加包含在SELECT中的列的索引(使用名称..)并运行您的查询,检查它们是否被使用,以及是否有性能改进。

代码语言:javascript
复制
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)您可以尝试混合解决方案、更简单的索引和复杂的查询。

代码语言:javascript
复制
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

以上每一项都要测试..。而且(也许)它可能是无用的。

我希望这将是有用的,了解一点,优化的大问题。

票数 0
EN

Stack Overflow用户

发布于 2018-04-10 08:50:44

请尝试更好的表现:

代码语言:javascript
复制
 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
票数 -1
EN

Stack Overflow用户

发布于 2018-04-10 09:04:52

由于单独的查询运行的时间与合并的查询一样长,所以我将继续使用合并的查询(即您也喜欢的第一个查询)。

查询中的唯一条件是日期,在一种情况下是TransactionDate,在另一种情况下是PostingDate。确保对它们有单独的索引,以便给予DBMS查找日期范围的选项:

代码语言:javascript
复制
create index idx_transact_transaction_date on tbltransactions(transactiondate);
create index idx_transact_posting_date on tbltransactions(postingdate);
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49749039

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档