问题描述: 有一个查询如下,去掉 TOP 1 的时候,很快就出来结果了,但加上 TOP 1 的时候,一般要 2~3 秒才出数据,何解? SELECT TOP 1 ??? A . INVNO FROM A , B WHERE A . Item = B . ItemNumber ??? AND B . OwnerCompanyCode IS NOT NULL ? 问题原因分

问题描述:

有一个查询如下,去掉

TOP 1

的时候,很快就出来结果了,但加上

TOP 1

的时候,一般要

2~3

秒才出数据,何解?

SELECT

TOP

1

???

A.

INVNO

FROM

A,

B

WHERE

A.

Item =

B.

ItemNumber

???

AND

B.

OwnerCompanyCode IS

NOT

NULL

?

问题原因分析:

在使用

TOP 1

的时候,

SQL Server

会尽力先找出这条

TOP 1

的记录,这就导致它采用了与不加

TOP

时不一致的扫描算法,

SQL Server

查询优化器始终认为,应该可以比较快的找到匹配的第

1

条记录,所以一般是使用嵌套循环的联接,则不加

TOP 1

时,

SQL Server

会根据结构和数据的统计信息决策出联接策略。

嵌套循环一般适用于联系的两个表,一个表的数据较大,而另一个表的数据较小的情况

,如果查询匹配的值出现在扫描的前端,则在取

TOP 1

的情况下,是符合嵌套循环联系的使用条件的,但当匹配的数据出现在扫描的后端,或者是基本上没有匹配的数据时,则嵌套循环要扫描完成两个大表,这显然是不适宜的,也正是因为这种情况,导致了

TOP 1

比不加

TOP 1

的效率慢很多

?

关于此问题的模拟环境:

USE

tempdb

GO

?

SET

NOCOUNT

ON

--======================================

--

创建测试环境

--======================================

RAISERROR

(

'

创建测试环境

'

,

10,

1)

WITH

NOWAIT

-- Table A

CREATE

TABLE

[dbo].

A(

???

[TranNumber] [int] IDENTITY

(

1,

1)

NOT

NULL,

???

[INVNO] [char](

8)

NOT

NULL,

???

[ITEM] [char](

15)

NULL

DEFAULT

(

''

),

???

PRIMARY

KEY

(

[TranNumber])

)

?

CREATE

INDEX

[indexONinvno] ON

[dbo].

A(

[INVNO])

CREATE

INDEX

[indexOnitem] ON

[dbo].

A (

[ITEM])

CREATE

INDEX

[indexONiteminnvo] ON

[dbo].

A(

[INVNO],

[ITEM])

GO

?

-- Table B

CREATE

TABLE

[dbo].

B(

???

[ItemNumber] [char](

15)

NOT

NULL

DEFAULT

(

''

),

???

[CompanyCode] [char] (

4)

NOT

NULL,

???

[OwnerCompanyCode] [char](

4)

NULL,

???

PRIMARY

KEY

(

[ItemNumber],

[CompanyCode])

)

?

CREATE

INDEX

[ItemNumber] ON

[dbo].

B(

[ItemNumber])

CREATE

INDEX

[CompanyCode] ON

[dbo].

B(

[CompanyCode])

CREATE

INDEX

[OwnerCompanyCode] ON

[dbo].

B(

[OwnerCompanyCode])

GO

?

--======================================

--

生成测试数据

--======================================

RAISERROR

(

'

生成测试数据

'

,

10,

1)

WITH

NOWAIT

INSERT

[dbo].

A(

[INVNO],

[ITEM])

SELECT

LEFT(

NEWID

(),

8),

RIGHT(

NEWID

(),

15)

FROM

syscolumns A,

syscolumns B

?

INSERT

[dbo].

B(

[ItemNumber],

[CompanyCode],

[OwnerCompanyCode])

SELECT

RIGHT(

NEWID

(),

15),

LEFT(

NEWID

(),

4),

LEFT(

NEWID

(),

4)

FROM

syscolumns A,

syscolumns B

GO

?

速度测试脚本:

--======================================

--

进行查询测试

--======================================

RAISERROR

(

'

进行查询测试

'

,

10,

1)

WITH

NOWAIT

DECLARE

@dt DATETIME

,

@id int

,

@loop int

DECLARE

@ TABLE

(

???

id int

IDENTITY

,

???

[TOP 1] int

,

???

[WITHOUT TOP] int

)

?

SET

@loop =

0

WHILE

@loop <

10

BEGIN

???

SET

@loop =

@loop +

1

???

RAISERROR

(

'test %d'

,

10,

1,

@loop)

WITH

NOWAIT

???

SET

@dt =

GETDATE

()

???????

SELECT

TOP

1

???????????

A.

INVNO

???????

FROM

A,

B

???????

WHERE

A.

Item =

B.

ItemNumber

???????????

AND

B.

OwnerCompanyCode IS

NOT

NULL

???

INSERT

@([TOP 1])

VALUES

(

DATEDIFF

(

ms,

@dt,

GETDATE

()))

???

SELECT

@id =

SCOPE_IDENTITY

(),

@dt =

GETDATE

()

???????

SELECT

--TOP 1

???????????

A.

INVNO

???????

FROM

A,

B

???????

WHERE

A.

Item =

B.

ItemNumber

???????????

AND

B.

OwnerCompanyCode IS

NOT

NULL

???

UPDATE

@ SET

[WITHOUT TOP] =

DATEDIFF

(

ms,

@dt,

GETDATE

())

???

WHERE

id =

@id

END

SELECT

*

FROM

@

UNION

ALL

SELECT

NULL,

SUM

(

[TOP 1]),

SUM

(

[WITHOUT TOP])

FROM

@

GO

?

测试数据的变更脚本:

DECLARE

@value char

(

15),

@value1 char

(

15)

SELECT

???

@value =

LEFT(

NEWID

(),

15),

???

@value1 =

LEFT(

NEWID

(),

15)

?

UPDATE

A

SET

Item =

@value

FROM

A

???

INNER

JOIN(

???????

SELECT

TOP

1

???????????

[TranNumber]

???????

FROM

(

???????????

SELECT

TOP

20

PERCENT

???????????????

[TranNumber]

???????????

FROM

A

???????????

ORDER

BY

[TranNumber]

???????

)

AA

???????

ORDER

BY

[TranNumber] DESC

???

)

B

???????

ON

A.

[TranNumber] =

B.

[TranNumber]

?

UPDATE

B

SET

ItemNumber =

@value

FROM

B

???

INNER

JOIN(

???

???

SELECT

TOP

1

???????????

[ItemNumber],

[CompanyCode]

???????

FROM

(

???????????

SELECT

TOP

20 PERCENT

???????????????

[ItemNumber],

[CompanyCode]

???????????

FROM

B

???????????

ORDER

BY

[ItemNumber],

[CompanyCode]

???????

)

BB

???????

ORDER

BY

[ItemNumber] DESC

,

[CompanyCode] DESC

???

)

B1

???????

ON

B.

[ItemNumber] =

B1.

[ItemNumber]

???????????

AND

B.

[CompanyCode] =

B1.

[CompanyCode]

GO

?

测试说明:

1.??

在刚建立好测试环境的时候,是没有任何匹配项的,这时候,

TOP 1

会扫描两个表的所有数据,运行“速度测试脚本

”可以看到此时有无

TOP 1

的效率差异:

TOP 1

明显比不加

TOP

2.??

修改“测试数据的变更脚本

”中,红色的

20

让匹配的数据出现在扫描的顶端、中间和尾端,分别使用

“速度测试脚本

”测试,可以看到,匹配的值靠近扫描的前端的时候,

TOP 1

比不加

TOP

快,随着匹配数据很后端的推移,这种效率差异会越来越小,到后面就变成

TOP 1

比不加

TOP 1

慢。

注意:

每次变更数据,并且完成“速度测试脚本

”测试后,需要修改“测试数据的变更脚本

”中,红色的

@

value

@value1

,让刚才设置匹配的数据再变回为不匹配

?

附:联接的几种方式

1.????

嵌套循环联接

嵌套循环联接也称为

嵌套迭代

,它将一个联接输入用作外部输入表(显示为图形执行计划中的顶端输入),将另一个联接输入用作内部(底端)输入表。外部循环逐行处理外部输入表。内部循环会针对每个外部行执行,在内部输入表中搜索匹配行。

最简单的情况是,搜索时扫描整个表或索引;这称为

单纯嵌套循环联接

。如果搜索时使用索引,则称为

索引嵌套循环联接

。如果将索引生成为查询计划的一部分(并在查询完成后立即将索引破坏),则称为

临时索引嵌套循环联接

。查询优化器考虑了所有这些不同情况。

如果外部输入较小而内部输入较大且预先创建了索引,则嵌套循环联接尤其有效。在许多小事务中(如那些只影响较小的一组行的事务),索引嵌套循环联接优于合并联接和哈希联接。但在大型查询中,嵌套循环联接通常不是最佳选择。

?

2.????

合并联接

合并联接要求两个输入都在合并列上排序,而合并列由联接谓词的等效

(ON)

子句定义。通常,查询优化器扫描索引(如果在适当的一组列上存在索引),或在合并联接的下面放一个排序运算符。在极少数情况下,虽然可能有多个等效子句,但只用其中一些可用的等效子句获得合并列。

由于每个输入都已排序,因此

Merge Join

运算符将从每个输入获取一行并将其进行比较。例如,对于内联接操作,如果行相等则返回。如果行不相等,则废弃值较小的行并从该输入获得另一行。这一过程将重复进行,直到处理完所有的行为止。

合并联接操作可以是常规操作,也可以是多对多操作。多对多合并联接使用临时表存储行。如果每个输入中有重复值,则在处理其中一个输入中的每个重复项时,另一个输入必须重绕到重复项的开始位置。

如果存在驻留谓词,则所有满足合并谓词的行都将对该驻留谓词取值,而只返回那些满足该驻留谓词的行。

合并联接本身的速度很快,但如果需要排序操作,选择合并联接就会非常费时。然而,如果数据量很大且能够从现有

B

树索引中获得预排序的所需数据,则合并联接通常是最快的可用联接算法。

?

3.????

哈希联接

哈希联接有两种输入:生成输入和探测输入。查询优化器指派这些角色,使两个输入中较小的那个作为生成输入。

哈希联接用于多种设置匹配操作:内部联接;左外部联接、右外部联接和完全外部联接;左半联接和右半联接;交集;联合和差异。此外,哈希联接的某种变形可以进行重复删除和分组,例如

SUM(salary) GROUP BY department

。这些修改对生成和探测角色只使用一个输入。

以下几节介绍了不同类型的哈希联接:内存中的哈希联接、

Grace

哈希联接和递归哈希联接。

内存中的哈希联接

希联接先扫描或计算整个生成输入,然后在内存中生成哈希表。根据计算得出的哈希键的哈希值,将每行插入哈希存储桶。如果整个生成输入小于可用内存,则可以

将所有行都插入哈希表中。生成阶段之后是探测阶段。一次一行地对整个探测输入进行扫描或计算,并为每个探测行计算哈希键的值,扫描相应的哈希存储桶并生成

匹配项。

Grace

哈希联接

如果生成输入大于内存,哈希联接将分为几步进行。这称为

“Grace

哈希联接

每一步都分为生成阶段和探测阶段。首先,消耗整个生成和探测输入并将其分区(使用哈希键上的哈希函数)为多个文件。对哈希键使用哈希函数可以保证任意两个

联接记录一定位于相同的文件对中。因此,联接两个大输入的任务简化为相同任务的多个较小的实例。然后将哈希联接应用于每对分区文件。

递归哈希联接

如果生成输入非常大,以至于标准外部合并的输入需要多个合并级别,则需要多个分区步骤和多个分区级别。如果只有某些分区较大,则只需对那些分区使用附加的分区步骤。为了使所有分区步骤尽可能快,将使用大的异步

I/O

操作以便单个线程就能使多个磁盘驱动器繁忙工作。

border: 1pt solid #dedfef; padding: 0cm

本文原创发布php中文网,转载请注明出处,感谢您的尊重!

mysql top 1效率_TOP 1比不加TOP慢的疑惑相关推荐

  1. SELECT TOP 1 比不加TOP 1 慢的原因分析以及SELECT TOP 1语句执行计划预估原理

    现实中遇到过到这么一种情况: 在某些特殊场景下:进行查询的时候,加了TOP 1比不加TOP 1要慢(而且是慢很多)的情况, 也就是说对于符合条件的某种的数据,查询1条(符合该条件)数据比查询所有(符合 ...

  2. TOP 1比不加TOP慢的疑惑

    问题描述: 有一个查询如下,去掉TOP 1的时候,很快就出来结果了,但加上TOP 1的时候,一般要2~3秒才出数据,何解? SELECT TOP 1 A.INVNO FROM A, B WHERE A ...

  3. 提高MySQL数据库查询效率的几个技巧(转载)

    [size=5][color=Red]提高MySQL数据库查询效率的几个技巧(转)[/color][/size]       MySQL由于它本身的小巧和操作的高效, 在数据库应用中越来越多的被采用. ...

  4. php pdo 与对比mysql,php使用mysqli和pdo扩展,测试对比连接mysql数据库的效率完整示例...

    php使用mysqli和pdo扩展,测试对比连接mysql数据库的效率完整示例 本文实例讲述了php使用mysqli和pdo扩展,测试对比连接mysql数据库的效率.分享给大家供大家参考,具体如下: ...

  5. 一个非常超级可爱的滚动到顶端(Back to top)的jQuery插件- jQuery Back to Top

    日期:2011/11/17  来源:GBin1.com 今天介绍一个非常可爱漂亮的滚动到顶端的插件,无需设置.它能快速的将页面里的元素添加滚动到顶端的功能.而且只在滚动时才出现,当滚动到顶端自动消失. ...

  6. stopped状态的进程 top 命令_30 个实例详解 TOP 命令!

    英文:Linoxide 编译:Linux中国/geekpilinux.cn/article-2352-1.html Linux中的top命令显示系统上正在运行的进程.它是系统管理员最重要的工具之一.被 ...

  7. TOP金服是钱包项目吗?TOP金服安全吗?TOP金服怎么盈利?

    TOP通证金服是什么?TOP通证金服怎么玩的?TOP通证金服怎么注册?   " 投资交易的未来是什么 ?"   " 是量化交易 !"   这是华尔街资深交易员. ...

  8. html里top是向下,css left right top bottom定位

    DIV CSS left right top bottom定位 这四个CSS属性样式用于定位对象盒子,必须定义position属性值为absolute或者relative此取值方可生效. 一.语法结构 ...

  9. top命令参数详解(linux top命令的用法详细详解)

    通过top命令可以有效的发现系统的缺陷出在哪里.是内存不够.CPU处理能力不够.IO读写过高. top命令输出长这样: top命令参数详解(linux top命令的用法详细详解) 以下解析一下各个字段 ...

最新文章

  1. java输出回文数原代码_JAVA怎么用循环语句编写一个判别是否为回文数的代码?...
  2. 【机器学习入门到精通系列】Octave在Mac上的下载安装和基本使用
  3. 好程序员大数据笔记之:Hadoop集群搭建
  4. 面试中你必须要知道的语言陷阱
  5. mysql占位符 防注入_php mysql中防注入的几个小问题,麻烦大大帮我解答谢谢
  6. php 输出读取结果集,php获取数据库结果集实例详解
  7. 前端学习(847):H5自定义属性
  8. [转]如何在.NET MVC中使用jQuery并返回JSON数据
  9. Jsoup解析html某片段的问题
  10. ajax回调给全局变量,jquery.Ajax回调成功后数据赋值给全局变量的问题
  11. 可视化model 参数
  12. 汇桔网与分众传媒正式达成全面深度战略资本合作
  13. 【数字基带信号】基于matlab三阶高密度双极型码【含Matlab源码 990期】
  14. 【苹果群发推iMessage苹果推】位置推在(delegate) 收到connectionDidFinishLoading
  15. 130 个相见恨晚的超实用网站,一次性分享出来
  16. 组合数学——插板模型
  17. 学习UI设计都需要会什么
  18. 联合证券|内外利好共振 今年A股可更乐观一点
  19. 微信小程序:2022强大的修复版趣味心理测试小程序源码,趣味测试引流裂变神器,流量主激励广告实现管道收益
  20. 密集子图挖掘算法的相关知识

热门文章

  1. matlab三角形分割,MATLAB 2014b及以上版本中带有画家渲染器的三角形拆分补丁
  2. java 寻找峰值峰谷_寻找峰值
  3. RuoYi-Cloud 部署篇_02(windows环境 mysql版本)
  4. 第8篇:Flowable快速工作流脚手架Jsite_请假实战_查看历史任务
  5. 软件设计师 - UML图
  6. 小程序开发(1)-之目录结构和文件说明
  7. java实现rsa欧几里得算法求d_RSA算法中利用欧几里得算法求d详细过程
  8. python中的json结构_python数据挖掘_Json结构分析
  9. pythonmysql查询转list_python 数据库查询结果转对象
  10. arcengine遍历属性表_Excel催化剂-遍历文件夹内文件信息特别是图像、音视频等特有信息...