如果我需要引用表记录的条件,如何创建高性能 SQL 选择查询?

Posted

技术标签:

【中文标题】如果我需要引用表记录的条件,如何创建高性能 SQL 选择查询?【英文标题】:How to create high performance SQL select query, if I need a condition for referrer table's records? 【发布时间】:2017-12-07 17:11:15 【问题描述】:

例如,我有 2 个表用于查询,PropertyMove 用于移动属性的历史记录。

我必须创建一个查询,该查询将返回所有属性 + 1 个额外的布尔列 IsInService,如果 Move 表有 DateTo = null 和 @ 的属性记录,它将具有值 true 987654332@(“服务中”)。

我创建了这个查询:

SELECT  
    [ID], [Name], 
    (SELECT COUNT(*) 
     FROM [Move]
     WHERE PropertyID = p.ID 
       AND DateTo IS NULL 
       AND MoveTypeID = 1) AS IsInService
FROM 
    [Property] as p
ORDER BY 
    [Name] ASC
OFFSET 100500 ROWS FETCH NEXT 50 ROWS ONLY;

我的 SQL 不是那么强,但据我所知,子查询是邪恶的 :)

如果预计这些表将包含数百万条记录,如何在我的情况下创建高性能 SQL 查询?

【问题讨论】:

改用连接,看看效果如何。 我不知道我必须使用哪个连接以及我必须如何使用才能获得我需要的结果 类似:select ID, Name, Count(*) as IsInService from Property p join Move m on p.ID = m.PropertyID where m.DateTo is null and m.MoveTypeID = 1 order by [Name] ASC OFFSET 100500 ROWS FETCH NEXT 50 ROWS ONLY; 也许你会用exists做得更好,例如:case when exists ( select 42 from ... ) then 1 else 0 end as IsInService @CodingYoshi 不行 【参考方案1】:

我已根据您的评论更新了代码。如果您需要其他内容,请提供预期的输入和输出数据。根据现有 cmets 的推断,这就是我能做的所有事情。此外,这并不是为了给你一个准确的工作解决方案。我的目的是给你一个原型,你可以从中构建你的解决方案。

也就是说:

下面的代码是您需要的基本连接。但是,请记住,索引在性能方面的作用可能与表和查询的结构一样重要。如果达到一定大小后索引不支持查询,那么如何查询表并不重要。网上有很多索引资源,但查看查询计划应该是您的首选。

请注意,您的列 [dbo].[Property] ([Name]) 可能应该是 NVARCHAR 以允许 SQL 最小化数据存储。该列上的索引会更小,搜索/更新更快。

DECLARE @Property AS TABLE
  (
       [ID]     INT
       , [Name] NVARCHAR(100)
  );

INSERT INTO @Property
            ([ID]
             , [Name])
VALUES      (1,N'A'),
            (2,N'B'),
            (3,N'C');

DECLARE @Move AS TABLE
  (
       [ID]           INT
       , [DateTo]     DATE
       , [MoveTypeID] INT
       , [PropertyID] INT
  );

INSERT INTO @Move
            ([ID]
             , [DateTo]
             , [MoveTypeID]
             , [PropertyID])
VALUES      (1,NULL,1,1),
            (2,NULL,1,2),
            (3,N'2017-12-07',1,2);

SELECT [Property].[ID]     AS [property_id]
       , [Property].[Name] AS [property_name]
       , CASE
             WHEN [Move].[DateTo] IS NULL
                  AND [Move].[MoveTypeID] = 1 THEN
                 N'true'
             ELSE
                 N'false'
         END               AS [in_service]
FROM   @Property AS [Property]
       LEFT JOIN @Move AS [Move]
              ON [Move].[PropertyID] = [Property].[ID]
WHERE  [Move].[DateTo] IS NULL
       AND [Move].[MoveTypeID] = 1; 

【讨论】:

如果您要为某些属性添加第二次移动,您会看到,该结果包含该属性的 2 行。但我只需要带有“IsInService”标志的属性列表

以上是关于如果我需要引用表记录的条件,如何创建高性能 SQL 选择查询?的主要内容,如果未能解决你的问题,请参考以下文章

要提高SQL查询效率where语句条件的先后次序应如何写

要提高SQL查询效率where语句条件的先后次序应如何写

如何传递从多个表创建的 PL/SQL 游标记录?

SQL 相同结构的多张表,如何联合查询符合条件的记录数?

sql中能使用 truncate实现有条件的删除吗?我试了试,好像不能。我需要确定一下,如果能,如何写。

Oracle SQL性能优化