邪恶花网站邪恶花_相关的子查询是“邪恶的”和“缓慢的”。 还是他们?

news/2024/5/10 10:13:08/文章来源:https://blog.csdn.net/danpu0978/article/details/107275401

邪恶花网站邪恶花

SQL中一个常见的神话是,相关子查询是邪恶且缓慢的。 例如,此查询在这里:

SELECT first_name, last_name,(SELECT count(*) FROM film_actor fa WHERE fa.actor_id = a.actor_id)
FROM actor a

它“强制”数据库引擎运行以下形式的嵌套循环(以伪代码):

for (Actor a : actor) {output(a.first_name,a.last_name,film_actor.where(fa -> fa.actor_id = a.actor_id).size()
}

因此,对于每个演员,请收集所有相应的film_actor并对其进行计数。 这将产生每个演员上演的电影数量。

似乎最好在“批量”中运行此查询,即运行:

SELECT first_name, last_name, count(*)
FROM actor a
JOIN film_actor fa USING (actor_id)
GROUP BY actor_id, first_name, last_name

但是真的更快吗? 如果是这样,您为什么会期望呢?

批量聚合与嵌套循环

在这种情况下,批量聚集实际上仅意味着我们正在收集所有actor和所有film_actor,然后将它们按操作分组存储在内存中。 执行计划(在Oracle中)如下所示:

-------------------------------------------------------------------
| Id  | Operation              | Name                    | A-Rows |
-------------------------------------------------------------------
|   0 | SELECT STATEMENT       |                         |    200 |
|   1 |  HASH GROUP BY         |                         |    200 |
|*  2 |   HASH JOIN            |                         |   5462 |
|   3 |    TABLE ACCESS FULL   | ACTOR                   |    200 |
|   4 |    INDEX FAST FULL SCAN| IDX_FK_FILM_ACTOR_ACTOR |   5462 |
-------------------------------------------------------------------

film_actor表中有5462行,对于每个演员,我们将它们合并并分组和汇总,以得到结果。 让我们将其与嵌套循环的计划进行比较:

-----------------------------------------------------------------------
| Id  | Operation         | Name                    | Starts | A-Rows |
-----------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                         |      1 |    200 |
|   1 |  SORT AGGREGATE   |                         |    200 |    200 |
|*  2 |   INDEX RANGE SCAN| IDX_FK_FILM_ACTOR_ACTOR |    200 |   5462 |
|   3 |  TABLE ACCESS FULL| ACTOR                   |      1 |    200 |
-----------------------------------------------------------------------

现在,我包括了“开始”行,以说明在收集了所有200个参与者之后,我们将子查询启动200次以获取每个参与者的计数。 但是这次,进行范围扫描。

仅从计划中,我们能说出哪个更快吗? 批量聚合将需要更多的内存(以加载所有数据),但是算法复杂度较低(线性)。 嵌套循环将需要更少的内存(所有必需的信息都可以直接从索引中获得),但是似乎具有更高的算法复杂度(二次)。

事实是,事实并非如此。

整体聚集确实是线性的,但是根据O(M + N),其中M =演员人数,N =电影演员人数,而嵌套循环不是二次方的,则为O(M log N)。 我们不需要遍历整个索引来获取计数。

在某些时候,较高的复杂性会更糟,但是由于只有少量的数据,所以不是:

在x轴上是N的大小,在y轴上是“复杂度值”,例如,算法使用了多少时间(或内存)。

复杂度-1

算法复杂度对大N的影响

算法复杂度对“小” N的影响

算法复杂度对“小” N的影响

以下是关于上述内容的免责声明:

“小N” =“在我的机器上工作”的算法复杂度

没有什么比用测量证明事情更好的了。 让我们运行以下PL / SQL程序:

SET SERVEROUTPUT ON
DECLAREv_ts TIMESTAMP;v_repeat CONSTANT NUMBER := 1000;
BEGINv_ts := SYSTIMESTAMP;FOR i IN 1..v_repeat LOOPFOR rec IN (SELECT first_name, last_name,(SELECT count(*) FROM film_actor fa WHERE fa.actor_id = a.actor_id)FROM actor a) LOOPNULL;END LOOP;END LOOP;dbms_output.put_line('Nested select: ' || (SYSTIMESTAMP - v_ts));v_ts := SYSTIMESTAMP;FOR i IN 1..v_repeat LOOPFOR rec IN (SELECT first_name, last_name, count(*)FROM actor aJOIN film_actor fa USING (actor_id)GROUP BY actor_id, first_name, last_name) LOOPNULL;END LOOP;END LOOP;dbms_output.put_line('Group by     : ' || (SYSTIMESTAMP - v_ts));
END;
/

经过三轮运行,并针对我们的标准Sakila数据库(在此处获取: https : //github.com/jOOQ/jOOQ/tree/master/jOOQ-examples/Sakila ),该数据库具有200个演员和5462个film_actors,我们可以看到嵌套的通过以下方式选择始终胜过批量销售组:

Nested select: +000000000 00:00:01.122000000
Group by     : +000000000 00:00:03.191000000Nested select: +000000000 00:00:01.116000000
Group by     : +000000000 00:00:03.104000000Nested select: +000000000 00:00:01.122000000
Group by     : +000000000 00:00:03.228000000

帮助优化者

Twitter上给出了Markus Winand( http://sql-performance-explained.com的作者)的一些有趣的反馈:

第三种选择:将GROUP BY操作嵌套在派生表中:

SELECTfirst_name, last_name, c
FROM actor a
JOIN (SELECT actor_id, count(*) cFROM film_actorGROUP BY actor_id
) USING (actor_id)

通过查询,与“普通”组相比,它产生的计划略好:

--------------------------------------------------------------------
| Id  | Operation               | Name                    | A-Rows |
--------------------------------------------------------------------
|   0 | SELECT STATEMENT        |                         |    200 |
|*  1 |  HASH JOIN              |                         |    200 |
|   2 |   TABLE ACCESS FULL     | ACTOR                   |    200 |
|   3 |   VIEW                  |                         |    200 |
|   4 |    HASH GROUP BY        |                         |    200 |
|   5 |     INDEX FAST FULL SCAN| IDX_FK_FILM_ACTOR_ACTOR |   5462 |
--------------------------------------------------------------------

像这样将其添加到基准中:

SET SERVEROUTPUT ON
DECLAREv_ts TIMESTAMP;v_repeat CONSTANT NUMBER := 1000;
BEGINv_ts := SYSTIMESTAMP;FOR i IN 1..v_repeat LOOPFOR rec IN (SELECTfirst_name, last_name,(SELECT count(*) FROM film_actor fa WHERE fa.actor_id = a.actor_id)FROM actor a) LOOPNULL;END LOOP;END LOOP;dbms_output.put_line('Nested select            : ' || (SYSTIMESTAMP - v_ts));v_ts := SYSTIMESTAMP;FOR i IN 1..v_repeat LOOPFOR rec IN (SELECTfirst_name, last_name, count(*)FROM actor aJOIN film_actor fa USING (actor_id)GROUP BY actor_id, first_name, last_name) LOOPNULL;END LOOP;END LOOP;dbms_output.put_line('Group by                 : ' || (SYSTIMESTAMP - v_ts));v_ts := SYSTIMESTAMP;FOR i IN 1..v_repeat LOOPFOR rec IN (SELECT first_name, last_name, cFROM actor aJOIN (SELECT actor_id, count(*) cFROM film_actorGROUP BY actor_id) USING (actor_id)) LOOPNULL;END LOOP;END LOOP;dbms_output.put_line('Group by in derived table: ' || (SYSTIMESTAMP - v_ts));
END;
/

…表明它已经非常接近嵌套的select选项:

Nested select            : +000000000 00:00:01.371000000
Group by                 : +000000000 00:00:03.417000000
Group by in derived table: +000000000 00:00:01.592000000Nested select            : +000000000 00:00:01.236000000
Group by                 : +000000000 00:00:03.329000000
Group by in derived table: +000000000 00:00:01.595000000

结论

我们已经表明,在某些情况下,相关子查询可能比批量聚合更好。 在Oracle中。 具有中小型数据集。 在其他情况下,这不是正确的,因为M和N的大小会增加我们的两个算法复杂度变量,因此O(M log N)会比O(M + N)差得多。

这里的结论是:不要相信任何最初的判断。 测量。 当您多次运行这样的查询时,慢3倍可以带来很大的不同。 但是也不要替换所有的批量聚合。

喜欢这篇文章吗? 内容是我们的Data Geekery SQL性能培训的一部分

翻译自: https://www.javacodegeeks.com/2016/05/correlated-subqueries-evil-slow.html

邪恶花网站邪恶花

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_732537.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何把自己的wordpress网站移到本地修改

有时候wordpress更换模板时,需要修改的地方很多,而且在线修改不是很好。只能把它移动到电脑本地进行修改了。这样修改好就可以直接套用到网站上了。 1、通过服务器控制面板或FTP整站打包,发送到你已经在电脑本地搭建ApachePHPMySQL环境的网站…

网站pv uv 停留时间 等统计

为什么80%的码农都做不了架构师?>>> 日志中心收集网站访问数据内容 基于nginx记录用户cookie的行为,进行分析 一、用户cookie。 需要创建3个cookie文件_gtra、_gtrb、_gtrc,其中_gtra用来追踪用户,_gtrb和_gtrc联合来…

手机网站的注意事项

2019独角兽企业重金招聘Python工程师标准>>> 一.web app 手机网站的注意事项: 1.安卓浏览器看背景图片,有些设备会模糊--> devicePixeRatio手机分辨率过小造成,解决方法使用2倍背景图代替img标签. 2.图片加载很慢--> 手机开发一般用canvas方法加载 3.手机端不…

《流量的秘密 Google Analytics网站分析与商业实战》一1.3 Google Analytics的地位

本节书摘来自异步社区《流量的秘密 Google Analytics网站分析与商业实战》一书中的第1章,第1.3节,作者 【英】Brian Clifton,更多章节内容可以访问云栖社区“异步社区”公众号查看 1.3 Google Analytics的地位 你的网站对你来说是极其重要的…

一个止传SWF的好网站

SwfCabin 是一個免費swf空間,最初建立的構想在於「如何在網路上將swf檔分享給別人」。使用者可以將swf檔上傳到 SwfCabin 然後獲得一個連結,其他人便可以在該頁面看到您所上傳的swf檔案。上傳檔案時 SwfCabin 會自動辨識該檔案最適當的顯示尺寸。除此之外…

大型网站架构之分布式缓存

缓存是优化网站性能的第一手段。在大型网站中,缓存通常用来保存热点数据,或者保存应用上下文相关信息。比如之前提到的session服务器集群就可以用分布式缓存来搭建。当然,分布式缓存还可用于缓存数据库中的热点数据以减轻数据库的压力。 分布…

决议要素_2020年每个网站测试人员的新年决议

决议要素您能够根据2019年的决议进行工作吗? 我在这里听起来可能很可笑,但是作为Web开发人员,我在2019年的决心是在业余时间跳入Web测试。 为什么? 因此,我可以从测试人员的角度了解发布周期。 我想穿他们的鞋子&#…

Thinking——nodejs实现的SEO相关的库

SEO SEO是为了网站在搜索引擎中的自然排名更靠前,引入更多的用户流量。SEO有很多技巧,譬如官网多发优质文章,文章的url做成静态化,文章多出现一些搜索相关的关键字,自建站群等等。 百度收录 百度定期会对优质文章进行收…

下拉框系统甄选火星推荐_seo关键词下拉框优化技术

“seo关键词下拉框优化技术,百度下拉框的算法,一个关键词每天有多少搜索量,和它相关的词有多少搜索量,这些数据百度都记录在案的,在百度搜索一个较短关键词的时候,下拉框中可能会出现一些和它相关的一些长尾词.”百度下拉框关键词指的是就是在百度搜索某一个关键词的时候&#…

大型网站架构演化历程

http://www.hollischuang.com/archives/728 本文内容大部分来自《大型网站技术架构》,这本书很值得一看,强烈推荐。 大型网站系统的特点 高并发,大流量 需要面对高并发用户,大流量访问。Google 日均 PV 35 亿,日 IP 访问数 3 亿&a…

SEO优化手工外链为什么更好?

开发十年,就只剩下这套Java开发体系了 >>> 手工发布的外链,是这个完结百度的网站权重与关键词排行优化的:咱 们通过手工在论坛/博客上回复主题帖子,并带有锚文体链接,这样的单向链接直接指 向你的网站&…

SEO核心技术纯白帽快速排名方法

我相信很多朋友都知道SEO快速排名,现在流行的快速排名都是众人皆知的黑帽SEO技术,但是却唯独不知道纯白帽也可以快速排名。但是我估计大家都看到过很多新站在短短数月内就上了首页,权重从0升到3,这难道是黑帽吗,不是的…

实验----实现基于LNMP的电子商务网站

实现基于LNMP的电子商务网站一、准备LNMP环境所需的包:yum install mariadb-server php-fpm php-mysql nginx二、准备网站:mkdir -p /data/web 建站点unzip -d /data/web xiaomi.zip 导入小米网站的源码包并解压到/data/webcd /data/web &…

pageSpeed Insights 图片对网站优化方案

2019独角兽企业重金招聘Python工程师标准>>> 一 规则 如下归纳几点 可供参考。<br> 避免使用着陆页面重定向 启用压缩功能 缩短服务器相应应用时间 使用浏览器缓存机智 缩短资源大小 优化图片 优化css发送过程 优化加载可见内容 移除会阻止呈现内容的javaScri…

网站常见问题1分钟定位 - 如何使用阿里云ARMS诊断Java应用卡顿问题

不要慌&#xff0c;上面只是一张贴图。为什么“慢”那么难查 网站卡顿、页面加载过慢是互联网应用最常见的问题之一。排查、解决这类问题通常会花费开发运维人员大量的时间&#xff0c;通常是因为以下三个原因&#xff1a;应用链路太长&#xff0c;无从下手。从前端页面到后台网…

JS网站图集相册特效

JS网站图集相册特效是一款可以直接使用鼠标进行前后导航&#xff0c;也可以通过缩略图来切换图片。在线演示本地下载转载于:https://www.cnblogs.com/wwhhq/p/8298797.html

手机移动端网站开发前要做的准备工作

为什么80%的码农都做不了架构师&#xff1f;>>> 现在的移动商城系统是商城网站必不可少的一部分&#xff0c;且占有相当比例的重要性&#xff0c;虽然手机商城网站开发很火&#xff0c;但是电商企业也不要盲目跟风&#xff0c;毕竟搭建一个商城系统网站也不是一下子…

利用angular4和nodejs-express构建一个简单的网站(三)—express访问mysql

在上一章中&#xff0c;我们为后端的express服务设置了跨域访问&#xff0c;并未前端的angular安装了bootstrap和ng-bootstrap依赖&#xff0c;并进行了配置&#xff0c;为后端的express安装了mysql和处理文件上传的multiparty依赖并创建了mysql数据库birthday在这一章中&#…

Python基础:有哪些网站可以做新手练习题?

答&#xff1a;有哪些网站可以做新手练习题&#xff1f; 练习 基础语法和实战项目 的 Python资源 有&#xff1a; Python经典练习题100道&#xff08;附链接&#xff09; http://www.pythonchallenge.com/ 这个网站的页面设计虽然不好看&#xff0c;但是里面的谜题设计得很出…

svn+nginx+mysql+php+nfs部署社交网站

操作环境&#xff1a;192.168.80.181 svn192.168.80.182 nginx192.168.80.183 mysql(MariaDB)192.168.80.185 php192.168.80.186 nfsSVN服务搭建 192.168.80.181:yum install -y subversionsvnserve --version //查看版本信息使用svnadmin建立版本库mkdir -p /opt/svn/rep…