我有一个相当大的表(约 170 万行)的优化问题。
选择行时使用了两列,我们称它们为 colA 和 colB。它们都是“ double ”类型(小数点后 5 位),范围从:
colA: -90 ~ 90 colB: -180 ~ 180
没有索引,任何形式的查询:
SELECT * FROM table where colA BETWEEEN a and b AND colB BETWEEN c and d
无论 (a,b) 和 (c,d) 的范围如何(因为 MySQL 必须检查每一行),运行时间大致相同(~ 1 秒)。
如果我向 colA 和 colB 添加索引,会发生两件事:查询 (a,b) & (c,d) 范围较小的地方,例如:
SELECT * FROM table where colA BETWEEEN -4 and 4 AND colB BETWEEN 3 and 7
运行非常快(~ 1/10 秒)。但是,执行时间会随着查询值之间的范围而增加。例如:
SELECT * FROM table where colA BETWEEEN -80 and 80 AND colB BETWEEN -150 and 150
执行大约需要一分钟。
我知道 B 树如何处理字符串,但我不确定数据为数字且使用范围进行查询时的机制。
如果有人可以建议如何优化此查询,我将不胜感激。一种想法是将索引用于小范围并告诉 MySQL 不要将它用于更大的范围,但是我找不到允许这样做的命令。
谢谢
编辑:解释
有件事我愚蠢地忘了提。结果按 rand() 排序 - 我知道这是多么低效,但我看不出有其他方法可以从表中随机获取有限数量的行。
添加 rand() 不会影响没有索引时的执行时间,但会大大增加有索引时的执行时间。
EDIT2:这是使用复合索引。
小范围:
“解释 select * from table where colA between 35 and 38 and colB between -10 and 5 ORDER BY RAND() LIMIT 20”
9783行
无索引(快)
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | table | ALL | NULL | NULL | NULL | NULL | 1673784 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
WITH INDEX(非常快)
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | table | range | test | test | 18 | NULL | 136222 | Using where |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
大范围:
“解释 select * from table where colA between -80 and 80 and colB between -150 and 150 ORDER BY RAND() LIMIT 20;”
1631862 行
无索引(快)
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | table | ALL | NULL | NULL | NULL | NULL | 1673784 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
WITH INDEX(非常慢:> 60 秒)
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | table | ALL | test | NULL | NULL | NULL | 1673784 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
编辑3:
总结:(所有查询限制为返回 20 行)
带有索引的 rand() 的大范围:45 秒
没有 rand() 的大范围,索引:0.003 秒
rand 大范围,无索引:1 秒
没有 rand 的大范围,没有索引:0.003 秒
异常是:“带有索引的 rand() 的大范围,45 秒”。
最佳答案
I know how B-trees works for strings, but I'm not sure of the mechanism when the data is numeric and the query is conducted using a range.
它们对数字的处理方式与对字符串的处理方式相同。
Without the index the query takes approximately the same time to run (~ 1 second), regardless of the range of (a,b), and (c,d)
全表扫描的运行时间不会随着 WHERE 条件的内容而显着变化。索引访问路径所花费的时间与返回的行数成正比。如果查询选择表的重要部分,使用索引总是比不使用索引慢。
索引访问路径只有在索引选择性足够时才是有效的,即检索的行数很少(有人说最多 10%)。执行时间将大致与返回的行数成正比,最终可能比全表扫描慢。
One thought is to use the index for small ranges and tell MySQL not to use it for larger ones, however I couldn't find a command which allows this.
查询优化器必须使用统计和启发式方法来确定是否应该使用索引。也许您需要使用 OPTIMIZE TABLE 更新这些统计信息.如果它仍然无法做出正确的决定,你可以帮助它 hints .
SELECT * FROM table
IGNORE INDEX (the_index)
where colA BETWEEEN -80 and 80 AND colB BETWEEN -150 and 150
其他选项可能是删除索引(如果您从未从中看到任何好处,恒定的一秒响应时间可能就足够了),或者尝试在两列上使用复合索引(也只有当从查询很小)。
既然您提到了 LIMIT 20,它就变得更有意义了:
big range with rand() with index: 45 seconds
有很多结果的嵌套循环 + 排序
从索引中获取所有记录(在范围内),从表中一条一条取出,然后排序,然后限制为20条
big range without rand(), with index: 0.003 seconds
嵌套循环在 20 条记录处中止
从索引中获取20条记录,从表中一条一条取出,返回。没有排序,实际上没有大范围。
big range with rand, no index: 1 second
全表扫描+排序
通读整个表,保持在范围内,然后排序,然后限制为20
big range without rand, no index: 0.003 seconds
全表扫描,在 20 条记录处中止
开始阅读表格,保持范围内的内容,当读到 20 时停止并返回。
关于数字列上的 MySQL 索引使查询变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4445854/
我正在用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.
我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问
我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新rubygems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems
我知道我可以指定某些字段来使用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
我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que
我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s
目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非
文章目录一、概述简介原理模块二、配置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中提取小时
我有一个.pfx格式的证书,我需要使用ruby提取公共(public)、私有(private)和CA证书。使用shell我可以这样做:#ExtractPublicKey(askforpassword)opensslpkcs12-infile.pfx-outfile_public.pem-clcerts-nokeys#ExtractCertificateAuthorityKey(askforpassword)opensslpkcs12-infile.pfx-outfile_ca.pem-cacerts-nokeys#ExtractPrivateKey(askforpassword)o