我有一个sql查询如下
select *
from incidents
where remote_ip = '192.168.1.1' and is_infringement = 1
order by reported_at desc
limit 1;
目前这个查询需要 313.24 秒才能运行。
如果我删除 order by 那么查询就是
select *
from incidents
where remote_ip = '192.168.1.1' and is_infringement = 1
那么运行只需要 0.117 秒。
reported_at 列已编入索引。
所以有 2 个问题,首先为什么这个 order_by 语句要花这么长时间,其次我怎样才能加快它的速度?
编辑:在回答下面的问题时,这里是使用 explain 时的输出:
'1', 'SIMPLE', 'incidents', 'index', 'uniqueReportIndex,idx_incidents_remote_ip', 'incidentsReportedAt', '4', NULL, '1044', '100.00', 'Using where'
建表语句:
CREATE TABLE `incidents` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`incident_ip_id` int(10) unsigned DEFAULT NULL,
`remote_id` bigint(20) DEFAULT NULL,
`remote_ip` char(32) NOT NULL,
`is_infringement` tinyint(1) NOT NULL DEFAULT '0',
`messageBody` text,
`reported_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Formerly : created_datetime',
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
UNIQUE KEY `uniqueReportIndex` (`remote_ip`,`host_id_1`,`licence_feature`,`app_end`),
UNIQUE KEY `uniqueRemoteIncidentId` (`remote_id`),
KEY `incident_ip_id` (`incident_ip_id`),
KEY `id` (`id`),
KEY `incidentsReportedAt` (`reported_at`),
KEY `idx_incidents_remote_ip` (`remote_ip`)
)
注意:我省略了一些不相关的字段,因此索引比字段多,但您可以安全地假设所有索引的字段都在表中
最佳答案
EXPLAIN 的输出显示,由于 ORDER BY 子句,MySQL 决定使用 incidentsReportedAt 索引。它按照索引提供的顺序从表数据中读取每一行,并检查其上的 WHERE 条件。这需要从表数据中读取大量信息,这些信息分散在整个表中。不是一个好的工作流程。
OP 在 reported_at 和 report_ip 列上创建了一个索引(如原始答案中所建议的,见下文),执行时间从 313 秒减少到 133 秒。有进步,但还不够。我认为执行时间仍然很长的原因是访问每一行的表数据以验证 WHERE 子句的 is_infringement = 1 部分,但甚至将其添加到索引不会有太大帮助。
OP 在评论中说:
Ok after further research and changing the index to be the other way round (
remote_ip,reported_at) the query is now super fast (0.083 sec).
这个索引确实更好,因为 remote_ip = '192.168.1.1' 条件过滤掉了很多行。 使用现有的 uniqueReportIndex 索引可以达到相同的效果。 reported_at 上的原始索引可能欺骗了 MySQL,使其认为最好用它来按照 ORDER BY 要求的顺序检查行,而不是先过滤,最后排序。
我认为 MySQL 在 (remote_ip, reported_at) 上使用新索引进行过滤 (WHERE remote_ip = '192.168.1.1') 并且用于排序(ORDER BY reported_at DESC)。 WHERE 条件提供了一个小的候选行列表,这些行很容易识别,也可以使用该索引进行排序。
原始答案如下。
它提供的建议不正确,但它帮助 OP 找到了正确的解决方案。
按顺序在 reported_at 和 report_ip 列上创建索引
然后看看 EXPLAIN 说了什么以及查询是如何执行的。它应该工作得更快。
您甚至可以在 reported_at、report_ip 和 is_infringement 列上创建新索引(索引中列的顺序非常重要) .
三列索引帮助MySQL识别行而不需要读取表数据(因为WHERE和ORDER BY子句的所有列都在索引中).由于 SELECT *,它只需要读取它返回的行的表数据。
创建新索引(在两列或三列上)后,删除旧索引 incidentsReportedAt。不再需要它了;它使用磁盘和内存空间,需要时间来更新,但未被使用。将改用新索引(第一个位置有 reported_at 列)。
在 is_infringement = 1 条件下,两列上的索引需要更多的表数据读取。查询可能比使用三列索引运行得慢一些。另一方面,表更新以及磁盘和内存空间使用量有所增加。
在两列或三列上建立索引的决定取决于问题中发布的查询运行的频率及其服务对象(访问者、管理员、cron 作业等)。
关于mysql - Order By 导致我的查询运行非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45209484/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
我正在用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.
在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
我知道我可以指定某些字段来使用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
GivenIamadumbprogrammerandIamusingrspecandIamusingsporkandIwanttodebug...mmm...let'ssaaay,aspecforPhone.那么,我应该把“require'ruby-debug'”行放在哪里,以便在phone_spec.rb的特定点停止处理?(我所要求的只是一个大而粗的箭头,即使是一个有挑战性的程序员也能看到:-3)我已经尝试了很多位置,除非我没有正确测试它们,否则会发生一些奇怪的事情:在spec_helper.rb中的以下位置:require'rubygems'require'spork'
我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西: