我正在浏览一个应用程序并尝试优化一些查询,但我真的很难处理其中的一些查询。这是一个例子:
SELECT `Item` . * , `Source` . * , `Keyword` . * , `Author` . * FROM `items` AS `Item` JOIN `sources` AS `Source` ON ( `Item`.`source_id` = `Source`.`id` ) JOIN `authors` AS `Author` ON ( `Item`.`author_id` = `Author`.`id` ) JOIN `items_keywords` AS `ItemsKeyword` ON ( `Item`.`id` = `ItemsKeyword`.`item_id` ) JOIN `keywords` AS `Keyword` ON ( `Keyword`.`id` = `ItemsKeyword`.`keyword_id` ) JOIN `keywords_profiles` AS `KeywordsProfile` ON ( `Keyword`.`id` = `KeywordsProfile`.`keyword_id` ) JOIN `profiles` AS `Profile` ON ( `Profile`.`id` = `KeywordsProfile`.`profile_id` ) WHERE `KeywordsProfile`.`profile_id` IN ( 17 ) GROUP BY `Item`.`id` ORDER BY `Item`.`timestamp` DESC , `Item`.`id` DESC LIMIT 0 , 20;
这个需要 10-30 秒...在引用的表中,大约有 50 万个作者行,以及大约 75 万个项目和 items_keywords 行。其他所有内容都少于 500 行。
这是解释输出: http://img.skitch.com/20090220-fb52wd7jf58x41ikfxaws96xjn.jpg
EXPLAIN 对我来说相对较新,但我逐行检查了这一点,一切似乎都很好。不确定我还能做什么,因为我对所有内容都有索引...我错过了什么?
它所在的服务器只是 slicehost 上的一个 256 分片,但上面没有其他任何东西在运行,并且 CPU 在它运行之前是 0%。然而它仍然在处理这个查询。有什么想法吗?
编辑:一些进一步的信息;真正令人沮丧的事情之一是,如果我重复运行此查询,它只需要不到 0.1 秒。我假设这是由于查询缓存,但如果我在它之前运行 RESET QUERY CACHE,它仍然运行得非常快。只有在我稍等片刻或运行其他一些查询后,10-30 秒才会返回。所有表都是 MyISAM...这是否表明 MySQL 正在将内容加载到内存中,这就是为什么它运行得如此之快的原因?
编辑 2:非常感谢大家的帮助……更新……我把所有内容都缩减为:
SELECT i.id FROM items AS i ORDER BY i.timestamp DESC, i.id DESC LIMIT 0, 20;
尽管数据库中只有 750k 条记录,但始终需要 5-6 秒。一旦我将第 2 列放在 ORDER BY 子句上,它几乎是即时的。显然这里发生了几件事,但是当我将查询缩减为:
SELECT i.id FROM items AS i JOIN items_keywords AS ik ON ( i.id = ik.item_id ) JOIN keywords AS k ON ( k.id = ik.keyword_id ) JOIN keywords_profiles AS kp ON ( k.id = kp.keyword_id ) WHERE kp.profile_id IN (139) ORDER BY i.timestamp DESC LIMIT 20;
仍然需要 10 多秒...我还能做什么?
次要的好奇心:在解释中,items_keywords 的行列始终为 1544,无论我在查询中使用什么 profile_id。它不应该根据与该个人资料关联的项目数量而改变吗?
编辑 3:好吧,这太荒谬了 :)。如果我完全删除 ORDER BY 子句,事情会非常迅速,并且临时表/文件排序从解释中消失。目前在 item.timestamp 列上有一个索引,但它是否由于某种原因没有被使用?我以为我记得一些关于 mysql 只使用每个表的索引之类的东西?我应该在该查询引用的项目表上的所有列(source_id、author_id、timestamp 等)上创建一个多列索引吗?
最佳答案
试试这个,看看效果如何:
SELECT i.*, s.*, k.*, a.*
FROM items AS i
JOIN sources AS s ON (i.source_id = s.id)
JOIN authors AS a ON (i.author_id = a.id)
JOIN items_keywords AS ik ON (i.id = ik.item_id)
JOIN keywords AS k ON (k.id = ik.keyword_id)
WHERE k.id IN (SELECT kp.keyword_id
FROM keywords_profiles AS kp
WHERE kp.profile_id IN (17))
ORDER BY i.timestamp DESC, i.id DESC
LIMIT 0, 20;
我将几个连接提取到一个不相关的子查询中,因此您不必执行 GROUP BY 将结果映射到不同的行。
实际上,在我的示例中,您可能仍会为每个 i.id 获取多行,具体取决于有多少关键字映射到给定项目以及 profile_id 17。
您的 EXPLAIN 报告中报告的 filesort 可能是由于 GROUP BY 和 ORDER BY 使用不同字段的组合。
我同意@ʞɔıu 的回答,加速可能是因为 key 缓存。
关于mysql - 这个查询有什么问题? EXPLAIN 对我来说很好,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/567991/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我正在用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.
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput
我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search