草庐IT

mysql查询成本比较

CXY_XZL 2023-03-28 原文

1.工具

1.mysql8.0.25
2.msyqlworkbench


2.成本定义

执行sql查询所需要花费的代价


3.查看成本的方式

执行一条示例语句,如下:

select sql_no_cache suser.id,suser.name ,srole.name from sys_user suser
 inner join sys_user_role surole on suser.id=surole.user_id
 inner join sys_role srole on surole.role_id=srole.id;

sql_no_cache:告诉mysql服务器不缓存这条语句的执行结果

执行完上面的sql语句后,再执行以下语句查看查询成本:

show status like 'last_query_cost';

执行结果截图如下:


查询成本.png

不过,workbench可以直接在执行计划中展示查询成本,截图如下:

workbench查看查询成本和执行计划.png

从执行计划中可以看到:
1.执行计划的第一步是查询stole表,而且是全表查询;
2.执行计划的第二部是查询surole表,也是全表查询;
3.执行计划的第三部是查询suser表,通过聚集索引查询,所以精确查找出一条匹配的数据;
4.srole表和surole表通过hash join关联查询数据,最终查出12条匹配的数据,然后和suer表的查询结果进行嵌套循环查询,前台循环查询的成本计算公式很简单,就是将潜逃的字查询的查询成本进行累加求和;
5.sql语句中,suser表是主表,然后依次关联surole表和srole表。但是,执行计划是先查询srole表,再查询surole表,最后查询suser表,两者顺序不同;
6.这是mysql优化器最终选择的它认为最优的执行计划;


4.sql的第二种写法

上面的sql可以用另一种写法,然后我们再看看新写法的查询成本
以下是新的写法:

select straight_join suser.id,suser.name ,srole.name from sys_user suser
 inner join sys_user_role surole on suser.id=surole.user_id
 inner join sys_role srole on surole.role_id=srole.id;

straight_join: 让mysql优化器按照sqljoin顺序来查询数据
现在我们再看一下查询成本及执行计划:

查询成本二.png

从上图可知:
1.现在的sql查询数据的顺序和执行计划是一致的;
2.最终查询成本是42.05,比优化器选择的执行计划的成本要高很多;


5.总结

1.从sql语句和执行计划可以看出,suser表全表只有12数据,srole表全表有4条数据,surole表全表有30条数据,如果suser表和srole表之间有关联字段的话,就能让这两张表做hash join关联查询,最后在与surole表做潜逃循环查询,这样的话,成本能比现在更低,但是,实际上,suser表和srole表之间并没有关联字段,所以这种假设不成立,感觉是在说废话...;
2.大多数情况下,优化器选择的执行计划都是查询成本最低的;


6.说明:

1.执行成本:执行成本为42.05的意思是,mysql认为大概需要做42个数据页的随机查找才能完成查询;
2.执行成本来源:执行成本是根据一系列的统计信息得来的,包括:每个表活着索引的页面个数、索引的基数(索引中不同值的数量)、索引和数据行的长度、索引分布情况;
3.优化器在评估成本的时候不会评估任何层面的缓存,包括mysql服务器内部的缓存,它假设读取任何数据都需要一次磁盘I/O;


7.mysql优化器在哪些情况戏会选择错误的(非最优的)执行计划

  • 统计信息不准确。mysql服务器依赖存储引擎提供的统计信息来评估成本,但是有的存储引擎提供的信息是准确的,比如myisam,有的则不准确,比如innodb
  • 执行计划中的成本估算不等同于实际执行的成本。即使统计信息准确,优化器给出的执行计划也可能不是最优的。有时候某个查询虽然需要读取更多的数据页,但是这些数据页都是顺序读活着已经在内存中,导致它的成本会更低。mysql并不知道哪些数据页是在内存中,哪些数据页是在磁盘上,所以查询在实际执行过程中的物理I/O次数是无从得知的。
  • mysql的最优和我们想要的最优可能不同。我们想要的最优的执行计划必然是能让查询最快的,但mysql是基于成本模型选择最优的执行计划。
  • mysql并不考虑查询兵法执行的情况。
  • mysql并不都是基于成本的优化,有时也会基于一些固定的规则。比如,存在全文搜索的match()子句,当有全文索引的时候,优化器就会选择全文索引来执行查询,即使用别的索引和where条件的查询会更快。
  • mysql不会考虑不受其控制的操作的成本。比如我么自定义的函数及存储过程。

有关mysql查询成本比较的更多相关文章

  1. ruby - ECONNRESET (Whois::ConnectionError) - 尝试在 Ruby 中查询 Whois 时出错 - 2

    我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.

  2. ruby - Ruby 的 Hash 在比较键时使用哪种相等性测试? - 2

    我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。

  3. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

  4. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  5. sql - 查询忽略时间戳日期的时间范围 - 2

    我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时

  6. ruby - 是否有用于复杂比较的漂亮语法? - 2

    方法应返回-1,0或1分别表示“小于”、“等于”和“大于”。对于某些类型的可排序对象,通常将排序顺序基于多个属性。以下是可行的,但我认为它看起来很笨拙:classLeagueStatsattr_accessor:points,:goal_diffdefinitializepts,gd@points=pts@goal_diff=gdenddefothercompare_pts=pointsother.pointsreturncompare_ptsunlesscompare_pts==0goal_diffother.goal_diffendend尝试一下:[LeagueStats.new(

  7. ruby-on-rails - 无法安装 mysql2 0.3.14 gem - 2

    我看到其他人也遇到过类似的问题,但没有一个解决方案对我有用。0.3.14gem与其他gem文件一起存在。我已经完全按照此处指示完成了所有操作:https://github.com/brianmario/mysql2.我仍然得到以下信息。我不知道为什么安装程序指示它找不到include目录,因为我已经检查过它存在。thread.h文件存在,但不在ruby​​目录中。相反,它在这里:C:\RailsInstaller\DevKit\lib\perl5\5.8\msys\CORE\我正在运行Windows7并尝试在Aptana3中构建我的Rails项目。我的Ruby是1.9.3。$gemin

  8. ruby-on-rails - solr 清理查询 - 2

    我在Rails上使用带有ruby​​的solr。一切正常,我只需要知道是否有任何现有代码来清理用户输入,比如以?开头的查询。或* 最佳答案 我不知道执行此操作的任何代码,但理论上可以通过查看parsingcodeinLucene来完成并搜索thrownewParseException(只有16个匹配!)。在实践中,我认为您最好只捕获代码中的任何solr异常并显示“无效查询”消息或类似信息。编辑:这里有几个“sanitizer”:http://pivotallabs.com/users/zach/blog/articles/937-s

  9. ruby-on-rails - Rails 3 在一个查询中包含多个表 - 2

    我正在为锦标赛开发一个Rails应用程序。我在这个查询中使用了三个模型:classPlayertruehas_and_belongs_to_many:tournamentsclassTournament:destroyclassPlayerMatch"Player",:foreign_key=>"player_one"belongs_to:player_two,:class_name=>"Player",:foreign_key=>"player_two"在tournaments_controller的显示操作中,我调用以下查询:Tournament.where(:id=>params

  10. ruby-on-rails - Sunspot:如何对具有不同值的多个字段进行全文查询? - 2

    我想用sunspot重现以下原始solr查询q=exact_term_text:fooORterm_textv:foo*ORalternate_text:bar*但我无法通过标准的太阳黑子界面理解这是否可能以及如何实现,因为看起来:fulltext方法似乎不接受多个文本/搜索字段参数我不知道将什么参数作为第一个参数传递给fulltext,就好像我通过了"foo"或"bar"结果不匹配如果我传递一个空参数,我得到一个q=*:*范围过滤器(例如with(:term).starting_with('foo*')(顾名思义)作为过滤器查询应用,因此不参与评分。似乎可以手动编写字符串(或者可能使

随机推荐