Docs说:
大多数MySQL索引(PRIMARY KEY,UNIQUE,INDEX和FULLTEXT)都存储在B树中。
所以物理上数据已经按键排序了。我在MySQL中需要一个带有范围查询支持的键值方案:
SELECT key, value FROM MyTable WHERE key >= key1 and key < key2;
在网络上的许多(大多数)示例中,我看到人们即使在使用主键进行选择时也会添加ORDER BY
。
我的问题:
SELECT key, value FROM MyTable WHERE key > key1 LIMIT 1;
会返回大于key1的下一个键,还是大于key1的任何键?如何可靠地获得LT,LE,GT,GE点查询?(在转向其他现有的基于B +树的KV存储之前,我需要在MySQL中接近'政治'和工具原因,我已经选择了最好的一个LMDB,所以问题只是关于在MySQL中模拟该方案)
答案 0 :(得分:3)
这里是否真的需要ORDER BY来使结果始终排序,如果是 - 为什么?
如果没有明确的ORDER BY
子句,MySQL 可能碰巧以所需的顺序返回结果 - 但是这种行为不能保证并且不能依赖(可能存在破坏行为的边缘情况,或者在未来的版本中可能会出现意外更改而没有任何警告。)
由于需要结果集始终要排序,因此必须添加明确的ORDER BY
子句。
排序会影响性能还是会被优化掉?
如果您有覆盖索引,即。一个在复合(key, value)
上定义的 - 然后您的问题中提到的确切查询将能够直接从该索引检索已排序的记录。 MySQL只需要遍历B树数据结构,找到所需的结果范围,然后返回它找到的内容。
如果你没有覆盖索引,那么一旦MySQL找到了属于过滤范围的key
值(使用索引),它就必须寻找表本身来检索每个关联的{{ 1}}。由于以磁盘顺序执行此操作的速度更快(以最大限度地减少IO抖动),MySQL可能不会使用索引进行排序,而是在结果上执行文件排序。我说“可能”,因为优化器可能会在某些边缘情况下做出不同的决定,具体取决于表大小,索引基数和/或存储引擎等。
您始终可以EXPLAIN
查询以查看优化程序已决定的执行计划,特别是是否会执行文件排序(仅当value
出现在Using filesort
时才会执行{1}}栏)。
如果值不是太大,将值作为复合索引的一部分是否有意义,例如只是数字?
如果你真的想要排序结果,那么(如上所示)你可能会发现覆盖索引的数据检索速度更快;当然,权衡是插入/更新会更慢。在您的案例中“有意义”将取决于您的申请的具体情况。
永远记住Knuth的格言:“过早优化是万恶之源。”我可能会在没有覆盖索引的情况下启动,只有在性能下降时才添加一个到了必要的程度。
在对结果集进行排序后(如果有的话)应用
Extra
会返回大于key1的下一个键,还是大于key1的任何键?如何可靠地获得LT,LE,GT,GE点查询?
SELECT key, value FROM MyTable WHERE key > key1 LIMIT 1;
。正如上面第一个项目中所解释的那样,如果没有明确的LIMIT
子句,结果将以未定义的顺序返回;因此,关于将由您的查询选择的单个记录可以说的是,它与“大于ORDER BY
的不确定密钥”有关。
要获取大于key1
的 next 键,您必须添加明确的key1
子句:
ORDER BY
对于“小于”查询,您必须明显反转排序顺序 - 例如:
SELECT key, value FROM MyTable WHERE key > key1 ORDER BY key LIMIT 1