【问题标题】:Optimize select query on huge database优化大型数据库的选择查询
【发布时间】:2017-08-30 20:35:03
【问题描述】:

我正在使用基于两个表(表 1 和表 2)的连接来开发 SQL 查询。RDBMS 是 SQL Server。两个表都有一个共同的ID 列,将基于该列形成连接。两列中还有一个日期时间列。

目标:我想从 Table2 中检索所有行,其中Table2.datetimeTable1.datetime 的 1 分钟范围内。

注意:我没有数据库的写权限,所以索引不是我的选择。

我答对了。它工作正常;但是,数据库很大。如果我想检索过去 15 天的数据,则需要很长时间。

有没有更好的方法呢?

这里是查询

SELECT
    A.Column1, A.Column2,
    A.Column3, A.Column4,
    A.Column5, A.Column6,
    A.Column7, A.Column8,
    A.Column9, A.Column10, A.Column11, 
    B.Column1, B.Column2,
    B.Column3, B.Column4, B.Column5 
FROM 
    TABLE1 A, TABLE2 B
WHERE 
    A.CommonColumn = B.CommonColumn 
    AND B.DateTime BETWEEN DATEADD(minute, -1, A.DateTime) 
                       AND DATEADD(minute, 1, A.DateTime)
    AND A.DateTime BETWEEN GETDATE() - 15 AND GETDATE()

【问题讨论】:

  • 您也许可以预先计算getdate()-15 并将其作为常数插入。否则,恐怕你没有权限优化情况。
  • 寻求性能帮助的问题应包括 DDL、DML 所涉及的表以及测试数据。如果您的测试数据很大,请尝试为表编写模式和统计信息(right click database->generate scripts->select specific database objects->in next screen select advanced and choose Script statistics) 并粘贴有问题..有了这些信息,任何人都可以重现您面临的相同问题。否则,回答您的问题变得非常困难。粘贴服务器版本也有帮助
  • @TheGameiswar 不要忘记执行计划。
  • 另外,如果在您删除时间标准时加入 不是 足够快(尝试一个简单的SELECT COUNT(*) FROM Table1 JOIN Table2 ON Table1.CommonColumn = Table2.CommonColumn),您可以停在那里:如果不能有效地完成,并且DateTime 列没有索引并且无法被索引,您的查询将永远无法执行。至少索引连接列。

标签: sql sql-server select optimization


【解决方案1】:

在应用分钟条件之前先尝试过滤数据以减少记录数 还为 startDate 和 endDate 定义变量,并在下面的查询中使用它们。(希望它有帮助,或者给你一个想法) (我担心 CTE 性能,但让我们试试)

Declare @startDate Datetime =GetDate()-15;
Declare @endDate Datetime=GetDate();

;with filteredDataA as (
SELECT A.CommonColumn,A.DateTime,
    A.Column1, A.Column2,
    A.Column3, A.Column4,
    A.Column5, A.Column6,
    A.Column7, A.Column8,
    A.Column9, A.Column10, A.Column11
FROM 
    TABLE1 A
where A.DateTime BETWEEN @startDate AND @endDate
),
filteredDataB as (
Select B.CommonColumn,B.DateTime,
B.Column1, B.Column2,
B.Column3, B.Column4, B.Column5
From Table2 B
where B.DateTime BETWEEN @startDate AND @endDate
)

Select A.Column1, A.Column2,
    A.Column3, A.Column4,
    A.Column5, A.Column6,
    A.Column7, A.Column8,
    A.Column9, A.Column10, A.Column11, 
    B.Column1, B.Column2,
    B.Column3, B.Column4, B.Column5

    from filteredDataA A left join filteredDataB  B on A.commonColumn=B.CommonColumn
    and B.DateTime BETWEEN DATEADD(minute, -1, A.DateTime) 
                        AND DATEADD(minute, 1, A.DateTime)

【讨论】:

  • 与流行的看法相反,使用 CTE 不会导致优化器根据 CTE 定义将查询拆分为“阶段”。查询将被折叠回主查询,就好像您在文本中将它们替换为子查询一样,然后整个优化。与原始查询相比,这不会“首先过滤数据”(或不会,取决于优化器认为最有效的方式)。在大多数情况下这是幸运的,否则这样的查询可能不会使用原始表上的索引。
【解决方案2】:

尝试更改第二个子句

WHERE 
A.CommonColumn = B.CommonColumn 
--AND B.DateTime BETWEEN DATEADD(minute, -1, A.DateTime) 
--                   AND DATEADD(minute, 1, A.DateTime)
AND ABS(DateDiff(mi, A.DateTime, B.DateTime)) <= 1
AND A.DateTime BETWEEN GETDATE() - 15 AND GETDATE()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-04
    • 2021-12-15
    • 1970-01-01
    • 2016-04-28
    • 1970-01-01
    • 1970-01-01
    • 2020-08-11
    相关资源
    最近更新 更多