AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 72094
Accepted
JohnLBevan
JohnLBevan
Asked: 2014-07-23 10:43:28 +0800 CST2014-07-23 10:43:28 +0800 CST 2014-07-23 10:43:28 +0800 CST

检查相关表中数据的性能

  • 772

注意:这个问题纯粹是学术性的/有助于提高我对 SQL Server 性能的理解。

给定一个与一个或多个其他表相关的主表,您将如何确定查询该主表以获取记录的最佳方法,其中包括相关表中记录存在的指示符?

例如,假设我们有一个 Person 表,想要获取所有人的列表以及他们是否有孩子的指标(在此示例中,Person 可以作为相关表重用):

create table Person
(
    Id bigint not null constraint pk_Person primary key clustered
    , ParentId bigint null constraint fk_Person_Parent foreign key references Person(Id)
    , FirstName nvarchar(256) not null
    , LastName nvarchar(256) not null
)

我们可以运行以下任何查询来检查相关子项的存在:

--variables for restricting our result set, just to keep things interesting
declare @LastName nvarchar(256) = 'Be%'
, @FirstName nvarchar(256) = null

示例 1

--  fairly straight forward, but requires grouping to account for the 
--  potential of a parent having multiple kids (which I don't care about here)
--  which could be adding some inefficiency.
select parent.Id
, parent.FirstName
, parent.LastName
, case when max(child.Id) is null then 0 else 1 end HasChildren
from Person parent
left outer join Person child --1:n
on child.ParentId = parent.Id
where (@LastName is null or parent.LastName like @LastName)
and (@FirstName is null or parent.FirstName like @FirstName)
group by parent.Id, parent.FirstName, parent.LastName --resolve 1:n

示例 2

--  avoid the need to group the results by first getting 
--  a single child per parent.
--  may be inefficient because we get children for all parents
--  even if we filter for only a few parents.
select parent.Id
, parent.FirstName
, parent.LastName 
, coalesce(child.hasChildren, 0) HasChildren
from Person parent
left outer join --1:? (0 or 1)
(
    select distinct parentId, 1 hasChildren
    from Person 
    where parentId is not null --not sure if this adds value
) child 
on child.ParentId = parent.Id
where (@LastName is null or LastName like @LastName)
and (@FirstName is null or FirstName like @FirstName)
--group by removed since we're 1:?

示例 3

--  same as #2 except we limit the child results to those 
--  related to the parents we're interested in / having stored
--  them in a CTE to avoid querying for the same parent data 
--  in the inner query and outer query.
--  Getting a bit silly now, but could overcome some inefficienies?
;with parentCTE as (
    select Id, FirstName, LastName 
    from person 
    where (@LastName is null or LastName like @LastName)
    and (@FirstName is null or FirstName like @FirstName)
)
select parentCTE.Id
, parentCTE.FirstName
, parentCTE.LastName 
, coalesce(child.hasChildren, 0) HasChildren
from parentCTE
left outer join --1:? (0 or 1)
(
    select distinct parentId, 1 hasChildren
    from Person 
    where parentId in --reduce the amount of data we return here based on the records we're interested in
    (
        select Id
        from parentCTE
    )
) child 
on child.ParentId = parentCTE.Id

例子 4

--  back to a simple one; just check for children on our parents 
--  but this time having brought back the full parent set.
--  may be inefficient because we're querying the table once per 
--  matching parent to check for children.
select parent.Id
, parent.FirstName
, parent.LastName
, coalesce((select top 1 1 from Person child where child.parentId = parent.Id),0) HasChildren
from Person parent
where (@LastName is null or LastName like @LastName)
and (@FirstName is null or FirstName like @FirstName)

我正在寻找有关如何更好地理解在这种情况下所涉及的权衡取舍的信息,而不是简单example 3的最好的。也欢迎指出可以帮助我理解的文章。

相关 SQL 小提琴:http ://sqlfiddle.com/#!6/edc17/3

sql-server performance
  • 1 1 个回答
  • 550 Views

1 个回答

  • Voted
  1. Best Answer
    stacylaray
    2014-07-23T21:40:02+08:002014-07-23T21:40:02+08:00

    示例 4 具有最少的扫描和读取:

    示例 1

    SQL Server 解析和编译时间:
        CPU 时间 = 4 毫秒,运行时间 = 4 毫秒。

    SQL Server 执行时间:CPU 时间 = 0 毫秒,耗用时间 = 0 毫秒。

    example1    Id    FirstName       
    -----------------------------
    1           2     Aaron           
    1           3     John            
    1           8     Aaron           
    1           9     John            
    1           14    Aaron           
    1           15    John            
    1           20    Aaron           
    1           21    John            
    

    (8 行受影响)

    表“人”。
    扫描计数 9,逻辑读取 27,物理读取 0,

    Rows                 Executes             StmtText                
    -------------------- -------------------- ------------------------
    8                    1                    select 1 example1
    
    , parent.Id
    , parent.FirstName
    , parent.LastName
    , case when max(child.Id) is null then 0 else 1 end HasChildren
    from Person parent
    left outer join Person child 
    on child.ParentId = parent.Id
    where (@LastName is null or parent.Las 1           1           0   
    0       0     |--Compute Scalar(DEFINE:([Expr1005]=(1), [Expr1
    8       1          |--Nested Loops(Left Outer Join, OUTER REFE
    8       1               |--Clustered Index Scan(OBJECT:([sub].
    3       8               |--Stream Aggregate(DEFINE:([Expr1004]
    7       8                    |--Clustered Index Scan(OBJECT:([
    

    (6 行受影响)

    SQL Server 执行时间:
        CPU 时间 = 0 毫秒,耗用时间 = 0 毫秒。

    示例 2

    SQL Server 解析和编译时间:CPU 时间 = 0 毫秒,耗用时间 = 4 毫秒。

    SQL Server 执行时间:
        CPU 时间 = 0 毫秒,耗用时间 = 0 毫秒。

    example2  Id   FirstName                                            
    ----------------------------
    2         2    Aaron                                                     
    2         3    John                                                      
    2         8    Aaron                                                     
    2         9    John                                                      
    2         14   Aaron                                                     
    2         15   John                                                      
    2         20   Aaron                                                     
    2         21   John         
    

    (8 行受影响)

    表“人”。
    扫描计数 9,逻辑读取 27,物理读取 0,

    Rows   Executes   StmtText                                         
    ------ ---------- -----------------------
    8      1          select 2 example2
    
    , parent.Id
    , parent.FirstName
    , parent.LastName 
    , coalesce(child.hasChildren, 0) HasChildren
    from Person parent
    left outer join 
    (
        select distinct parentId, 1 hasChildren
        from Person 
        where parentId is not null 
    ) child 
    
     1           1           0           NULL                          
    0     0       |--Compute Scalar(DEFINE:([Expr1007]=(2), [Expr1
    8     1            |--Nested Loops(Left Outer Join, OUTER REFE
    8     1                 |--Clustered Index Scan(OBJECT:([sub].
    3     8                 |--Stream Aggregate(DEFINE:([Expr1006]
    0     0                      |--Compute Scalar(DEFINE:([Expr10
    7     8                           |--Clustered Index Scan(OBJE
    

    (7 行受影响)

    SQL Server 执行时间:CPU 时间 = 0 毫秒,耗用时间 = 0 毫秒。

    示例 3

    SQL Server 解析和编译时间:CPU 时间 = 7 毫秒,运行时间 = 7 毫秒。

    SQL Server 执行时间:CPU 时间 = 0 毫秒,耗用时间 = 0 毫秒。

    example3 Id   FirstName                                            
    ---- ------ ------------------------
    3    2      Aaron                                                  
    3    3      John                                                   
    3    8      Aaron                                                  
    3    9      John                                                   
    3    14     Aaron                                                  
    3    15     John                                                   
    3    20     Aaron                                                  
    3    21     John   
    

    (8 行受影响)

    表“人”。扫描计数 9,逻辑读取 41,物理读取 0,r

    Rows     Executes   StmtText                                       
    ------   ---------  ------------------
    8        1          with parentCTE as (
        select Id, FirstName, LastName 
        from person 
        where (@LastName is null or LastName like @LastName)
        and (@FirstName is null or FirstName like @FirstName)
    )
    select 3 example3
    , parentCTE.Id
    , parentCTE.FirstName
    , parentCTE.La 1           1           0           NULL            
    0     0     |--Compute Scalar(DEFINE:([Expr1011]=(3), [Expr1
    8     1          |--Nested Loops(Left Outer Join, OUTER REFE
    8     1               |--Clustered Index Scan(OBJECT:([sub].
    3     8               |--Stream Aggregate(DEFINE:([Expr1010]
    0     0                    |--Compute Scalar(DEFINE:([Expr10
    7     8                         |--Nested Loops(Inner Join, 
    7     8                              |--Clustered Index Scan
    7     7                              |--Clustered Index Seek
    

    (9 行受影响)

    SQL Server 执行时间:CPU 时间 = 0 毫秒,耗用时间 = 0 毫秒。

    例 4

    SQL Server 解析和编译时间:CPU 时间 = 3 毫秒,运行时间 = 3 毫秒。

    SQL Server 执行时间:CPU 时间 = 0 毫秒,耗用时间 = 0 毫秒。

    example4 Id  FirstName                                             
    ---- ----- -------------
    4    2     Aaron        
    4    3     John         
    4    8     Aaron        
    4    9     John         
    4    14    Aaron        
    4    15    John         
    4    20    Aaron        
    4    21    John         
    

    (8 行受影响)

    表“人”。扫描计数 3,逻辑读取 26,物理读取 0,

    Rows     Executes   StmtText             
    -------- ---------- ---------------------
    8        1          select 4 example4
    , parent.Id
    , parent.FirstName
    , parent.LastName
    , coalesce((select top 1 1 from Person child where child.parentId =
    from Person parent
    where (@LastName is null or LastName like @LastName)
    and (@FirstName  1           1           0           NULL          
    0       0     |--Compute Scalar(DEFINE:([Expr1002]=(4), [Expr1
    8       1          |--Nested Loops(Left Outer Join, PASSTHRU:(
    8       1               |--Nested Loops(Left Outer Join, OUTER
    8       1               |    |--Clustered Index Scan(OBJECT:([
    0       0               |    |--Compute Scalar(DEFINE:([Expr10
    3       8               |         |--Top(TOP EXPRESSION:((1)))
    3       8               |              |--Clustered Index Scan
    0       0               |--Compute Scalar(DEFINE:([Expr1008]=(
    3       3                    |--Top(TOP EXPRESSION:((1)))     
    3       3                         |--Clustered Index Scan(OBJE
    

    (11 行受影响)

    SQL Server 执行时间:CPU 时间 = 0 毫秒,耗用时间 = 0 毫秒。

    您希望扫描次数尽可能少。我们扫描表格的次数越多,花费的时间就越长。

    • 3

相关问题

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

  • 我在哪里可以找到mysql慢日志?

  • 如何优化大型数据库的 mysqldump?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve