在 MySQL 5.6 DB 中,我有一个具有以下结构的巨大 SQL 表:
CREATE TABLE `tbl_requests` (
`request_id` BIGINT(20) UNSIGNED NOT NULL,
`option_id` BIGINT(20) UNSIGNED NOT NULL,
`symbol` VARCHAR(30) NOT NULL,
`request_time` DATETIME(6) NOT NULL,
`request_type` SMALLINT(6) NOT NULL,
`count` INT(11) NOT NULL,
PRIMARY KEY (`request_id`),
INDEX `key_request_type_symbol` (`request_type`, `symbol`),
INDEX `key_request_time` (`request_time`),
INDEX `key_request_symbol` (`symbol`)
);
表中有超过 8 亿条记录,symbol 字段约有 25,000 种,request_type 中有约 100 个不同的值。我的目标是尽可能快地进行如下查询:
SELECT tbl_requests.*
FROM tbl_requests use index (key_request_type_symbol)
-- use index (key_request_time) -- use index (key_request_type_symbol)
WHERE (tbl_requests.request_time >= '2016-02-23' AND
tbl_requests.request_time <= '2016-12-23')
AND (tbl_requests.request_type IN (0, 1, 9))
[AND (tbl_requests.symbol = 'AAPL' ... )]
ORDER BY tbl_requests.request_time DESC, tbl_requests.request_id DESC
LIMIT 0,100;
通过 tbl_requests.symbol 字段进行不同种类的过滤,从无过滤器到一组值再到一组匹配模式再到混合匹配。
我看到的是不同的索引在不同的情况下给出了最好的性能,MySQL 无法猜测哪个更好。例如,在没有过滤器的情况下,最快的是 key_request_time 索引(0.016 秒),MySQL 正确地选择了它(EXPLAIN 命令的结果):
"id": 1, "select_type": "SIMPLE", "table": "tbl_requests", "type": "range", "possible_keys": "key_request_type_symbol,key_request_time", "key": "key_request_time", "key_len": "8", "ref": null, "rows": 428944675, "Extra": "Using index condition; Using where"
如果使用索引 key_request_type_symbol 索引,则此查询将花费大量时间(可能是几个小时?)。
我使用语法
FROM tbl_requests use index (key_request_type_symbol)
强制使用索引。
当过滤器中使用一个符号时
AND (tbl_requests.symbol = 'BAC')
MySQL 服务器正在选择相同的 key_request_time 索引,查询时间超过 10 秒。但是如果使用 key_request_type_symbol 索引,查询大约需要 0.7 秒。此外,当使用第一个索引时,如果再次重复查询,它会持续占用 10 秒以上,而当使用第二个索引时,重复查询需要 0.1 秒。
key_request_type_symbol 索引的解释信息:
"id": 1, "select_type": "SIMPLE", "table": "tbl_requests", "type": "range", "possible_keys": "key_request_type_symbol", "key": "key_request_type_symbol", "key_len": "34", "ref": null, "rows": 17117, "Extra": "Using index condition; Using where; Using filesort"
行数少了很多,但有文件排序。
在 key_request_type_symbol 的情况下,表中有多少匹配行很重要。对于“AMZN”符号,行数 = 79762,时间为 0.15 秒,而如果使用 key_request_time 索引,则需要 4.4 秒。但是 MySQL 比 key_request_type_symbol 更喜欢它。
在下面的例子中可以看得很清楚。如果我使用:
tbl_requests.symbol LIKE 'A%'
使用 key_request_time 索引需要 0.172 秒。
使用 key_request_type_symbol 索引需要 173 秒。 (约慢 1000 倍)
行=6367732
对于:
tbl_requests.symbol LIKE 'AM%'
使用 key_request_time 索引需要 0.640 秒。
使用 key_request_type_symbol 索引需要 2.2 秒。 (约慢 3 倍)
行=838822
对于:
tbl_requests.symbol LIKE 'AMZ%'
使用 key_request_time 索引需要 4.5 秒。
使用 key_request_type_symbol 索引需要 0.15 秒。 (快约 30 倍)
行=73083
对于:
tbl_requests.symbol LIKE 'AMZN%'
使用 key_request_time 索引需要 4.4 秒。
使用 key_request_type_symbol 索引需要 0.15 秒。 (快约 30 倍)
行=79762
此外,当使用 key_request_type_symbol 索引时,再次使用相同的符号过滤器时执行速度会更快,而 key_request_time 时序保持大致相同。
我将收到很多关于一个符号的查询,所以我需要他们尽快。但我也可能会收到由许多符号过滤的查询。如何强制服务器在每种情况下为我选择最快的方式?
我能想到的一种方法是提前发送 EXPLAIN 语句并检查 key_request_type_symbol 索引情况下的预期行数,然后修改查询以相应地使用这个或那个索引(比如,如果行数超过 300000,请使用 key_request_time)。
但也许我遗漏了什么?也许索引不正确(但我找不到更好的)?保持查询不变并强制 MySQL 足够智能以自动选择最快的方式会很好。
最佳答案
这是您遗漏的有关 MySQL 如何使用索引的规则:
symbol = 'AAPL' )。您可以有多个列,只要它们都满足相等条件即可。<> , > , < , IN() , BETWEEN , LIKE没有前导通配符,或 IS [NOT] NULL .GROUP BY或 ORDER BY ,但如果您对范围条件使用了索引,则不会。基本上,在进行相等性测试的列之后,您的索引中会多一列。示例:假设您有一个具有以下条件的查询:
WHERE a = 1 AND b = 2 AND c > 3 AND d IN (4,5,6)
假设您在 (a, b, c, d) 上按顺序有一个索引。只有索引中的 a、b、c 列将有助于查询。由于 c 列处于不等式比较中,因此索引中的最后一列有帮助。
(实际上,InnoDB 最近有一个称为“索引条件下推”的功能,它可能允许存储引擎通过搜索 d 的值来提供更多帮助,但不要指望它与常规索引查找一样好。我在你的一个 EXPLAIN 输出中看到了注释“使用索引条件”,表明它正在使用这个特性。阅读 http://dev.mysql.com/doc/refman/5.7/en/index-condition-pushdown-optimization.html 了解更多细节。)
同样,由于 c 的不等式条件,此查询将无法使用 d 来避免以下查询中的文件排序。
WHERE a = 1 AND b = 2 AND c > 3
ORDER BY d
而以下将能够使用 d 来优化排序,因为一旦查询找到 c=3 的行子集,那么其余匹配项自然会按 d 顺序读取。
WHERE a = 1 AND b = 2 AND c = 3
ORDER BY d
现在了解如何将其应用于您的查询:
WHERE (tbl_requests.request_time >= '2016-02-23' AND
tbl_requests.request_time <= '2016-12-23')
AND (tbl_requests.request_type IN (0, 1, 9))
[AND (tbl_requests.symbol = 'AAPL' ... )]
ORDER BY tbl_requests.request_time DESC, tbl_requests.request_id DESC
符号的条件是相等。它应该位于索引的最左侧。
request_time 和request_type 的条件都是不等的。您只能从索引中的一个或另一个中受益。选择最选择性的那个——它能最好地缩小搜索范围。将另一列添加到索引中以防万一 ICP 可以提供一点帮助。
我猜想在大多数情况下,request_time 列更具选择性。我看到你的条件是 10 个月的范围,这可能是你表格的大部分内容,但根据你选择的日期范围,它可能会更窄。
同样,request_type 的三个值 0、1、9 也可能匹配表中的大部分行。如果是这样,那么该条件就不会非常有选择性,我会将该列放在最后。
ALTER TABLE tbl_requests ADD INDEX (symbol, request_time, request_type);
顺序 request_time 发生在不等式条件之后,因此无法避免对匹配行进行文件排序,抱歉。
关于mysql - 使 MySQL 为查询选择最佳索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41027297/
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我正在用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.
我主要使用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
我知道我可以指定某些字段来使用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
状态:我正在构建一个应用程序,其中需要一个可供用户选择颜色的字段,该字段将包含RGB颜色代码字符串。我已经测试了一个看起来很漂亮但效果不佳的。它是“挑剔的颜色”,并托管在此存储库中:https://github.com/Astorsoft/picky-color.在这里我打开一个关于它的一些问题的问题。问题:请建议我在Rails3应用程序中使用一些颜色选择器。 最佳答案 也许页面上的列表jQueryUIDevelopment:ColorPicker为您提供开箱即用的产品。原因是jQuery现在包含在Rails3应用程序中,因此使用基
文章目录一、概述简介原理模块二、配置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
我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时
我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来
我发现自己需要这个。假设cart是一个包含用户列表的模型。defindex_of_itemcart.users.each_with_indexdo|u,i|ifu==current_userreturniendend获取此类关联索引的更简单方法是什么? 最佳答案 indexArray上的方法与您的index_of_item方法相同,例如cart.users.index(current_user)返回数组中第一个对象的索引==给obj。如果未找到匹配项,则返回nil。 关于ruby-on-
我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion