SQL查询复杂性对性能有什么一般规律吗?

时间:2010-01-14 16:38:03

标签: sql performance big-o

1)如果未使用索引,SQL查询执行时间O(n)是否与连接数相比较?如果没有,我们可能会期待什么样的关系?并且索引可以改善实际的大O时间复杂度,还是仅仅通过某个常数因子减少整个查询时间?

稍微含糊的问题,我确信它变化很大但我在这里谈论的是一般意义。

2)如果您有类似的查询:

SELECT  T1.name, T2.date
FROM    T1, T2
WHERE   T1.id=T2.id
        AND T1.color='red'
        AND T2.type='CAR'

我是否正确假设DB在评估多表条件之前首先在T1.color和T2.type上进行单表过滤?在这种情况下,使查询更复杂可以使它更快,因为更少的行受到连接级别的测试?

4 个答案:

答案 0 :(得分:44)

这取决于使用的查询计划。

即使没有索引,现代服务器也可以使用比HASH JOIN更快的MERGE JOINO(N * M)

更具体地说,HASH JOIN的复杂性为O(N + M),其中N是散列表,M是查找表。散列和散列查找具有不变的复杂性。

MERGE JOIN的复杂性为O(N*Log(N) + M*Log(M)):它是对两个表进行排序的时间加上扫描它们的时间。

SELECT  T1.name, T2.date
FROM    T1, T2
WHERE   T1.id=T2.id
        AND T1.color='red'
        AND T2.type='CAR'

如果没有定义索引,引擎将选择HASH JOINMERGE JOIN

HASH JOIN的工作原理如下:

  1. 选择散列表(通常是具有较少记录的表)。说它是t1

  2. 扫描t1的所有记录。如果记录保持color='red',则此记录将进入哈希表,其中id为关键字,name为值。

  3. 扫描t2的所有记录。如果记录保持type='CAR',则在哈希表中搜索其id,并返回所有哈希命中的name值以及当前值data。< / p>

  4. MERGE JOIN的工作原理如下:

    1. 创建t1 (id, name)的副本,按id

    2. 排序
    3. 创建t2 (id, data)的副本,按id

    4. 排序
    5. 指针在两个表中都设置为最小值:

      >1  2<
       2  3
       2  4
       3  5
      
    6. 指针在循环中进行比较,如果匹配,则返回记录。如果它们不匹配,则具有最小值的指针会提前:

      >1  2<  - no match, left pointer is less. Advance left pointer
       2  3
       2  4
       3  5
      
       1  2<  - match, return records and advance both pointers
      >2  3
       2  4
       3  5
      
       1  2  - match, return records and advance both pointers
       2  3< 
       2  4
      >3  5
      
       1  2 - the left pointer is out of range, the query is over.
       2  3
       2  4<
       3  5
      >
      
    7.   

      在这种情况下,使查询更复杂可以使它更快,因为更少的行受到连接级别的测试?

      不确定

      没有WHERE子句的查询:

      SELECT  T1.name, T2.date
      FROM    T1, T2
      

      更简单但返回更多结果并运行更长时间。

答案 1 :(得分:15)

小心混淆太多不同的东西。根据要检查的行数,您有一个逻辑成本,基于实际返回的行数(可能)较小的逻辑成本,以及基于必须检查的页数的无关物理成本。

这三者是相关的,但并不强烈。

检查的行数是这些成本中最大的,并且最不容易控制。必须通过连接算法匹配行。这也是最不相关的。

返回的行数更加昂贵,因为它是客户端应用程序和数据库之间的I / O带宽。

读取的页数是最昂贵的,因为这是更多的物理I / O.这是最昂贵的,因为数据库中的负载会影响所有客户端。

一个表的SQL查询是 O n )。那是行数。根据页数,它也是 O p )。

对于多个表,检查的行是 O (n m ...)。这是嵌套循环算法。但是,根据关系的基数,结果集可能与 O n )一样小,因为关系都是1:1。但是必须检查每个表的匹配行。

散列连接用 O (n)直接散列查找替换 O (n * log(n))索引+表读取。您仍然需要处理 O n )行,但是您可以绕过一些索引读取。

合并连接用 O (log(n + m)(n + m))替换 O (n m)嵌套循环排序操作。

对于索引,如果仅检查表是否存在,则物理成本可能会降低为 O (log(n) m)。如果需要行,则索引会加快对行的访问,但必须处理所有匹配的行。 O (n m),因为这是结果集的大小,与索引无关。

根据索引的选择性,检查此工作的页面可能更小。

索引的重点不是减少检查的行数。这是为了减少获取行的物理I / O成本。

答案 2 :(得分:1)

  

如果未使用索引,SQL查询执行时间O(n)是否与连接数相比较?

通常它们将是O(n ^ m),其中n是每个表所涉及的记录数,m是要连接的表的数量。

  

并且索引可以改善实际的大O时间复杂度,还是仅仅通过某个常数因子减少整个查询时间?

两者。当连接被大量过滤时(即具有良好的WHERE子句),索引允许直接查找,并且当它们位于右列时,它们允许更快的连接。

当索引不在要加入或过滤的列上时,索引没有帮助。

答案 3 :(得分:0)

查看clusterednon-clustered indexes的工作方式

这是从纯粹的技术角度来看...为了一个简单的解释,我的好朋友mladen编写了一个简单的article to understand索引。

索引肯定有帮助,但我建议阅读以了解其优缺点。