2016-08-13 94 views
-4

可怜我有一个非常简单的表有三列:MySQL的 - 在选择业绩从一个简单的表格

- A BigINT, 
- Another BigINT, 
- A string. 

前两列被定义为索引,也没有重复。而且,这两列的价值都在增长。

该表有近400K条记录。

我需要选择字符串时的值是内的那些塔1和两个,为了词:

SELECT MyString 
    FROM MyTable 
WHERE Col_1  <= Test_Value 
    AND Test_Value <= Col_2  ; 

结果可以是找不到或单个值。

查询需要几乎整整一秒的时间,而直觉上(想象一个数组中的二进制搜索),它应该只需要一小段时间。

我检查了索引类型,它是两列(1和2)的BTREE。

任何想法如何提高性能?

在此先感谢。

编辑: 的解释如下:

选择类型:简单, 类型:范围, 可能的关键字:PRIMARY 重点:小学, 密钥长度:8, 行:441, 已过滤:33.33 , 额外:使用where。

+3

有复合索引? – YOU

+0

在寻求绩效建议时,有必要展示确切的表格结构和索引。使用EXPLAIN命令来让查询计划者描述它正在做什么也是有帮助的。请[编辑]您的问题以包含这些项目。 –

+0

没有复合索引@YOU。 – FDavidov

回答

2

如果我正确理解你的混淆,你有一个startend的值,例如一对列中的日期时间或IP地址?你想看看你的给定的日期时间/ IP是否在给定的范围内?

那么,没有办法在这样的表上一般地优化这样的查询。优化器不知道给定的值是否可以在多个范围内。或换句话说,范围是否不相交。

因此,优化器最好使用从startend开始的索引,并扫描一半的表格。效率不高。

范围是否重叠? IP Addresses

对结果有什么看法?也许这样的一个kludge将工作:SELECT ... WHERE Col_1 <= Test_Value ORDER BY Col_1 DESC LIMIT 1

+0

谢谢@RickJames的回答。添加'ORDER'和'LIMIT'会产生很大的不同,需要进一步的测试,当达到最终结果时会更新,按照IP地址,不是,但是很像。 – FDavidov

1

您的查询,用较短的标识符改写,这是

SELECT s FROM t WHERE t.low <= v AND v <= t.high 

要使用索引会是这样的满足这个查询:首先,我们必须寻找到符合第一这些标准

所有行的表或索引
t.low <= v 

我们可以认为这是BTREE索引的半扫描。它从一开始就开始,到达v时停止。

它需要在的另一个半扫描以满足v <= t.high。然后它需要合并两个结果集来确定符合两个条件的行。问题是,合并的两个结果集很大,并且几乎完全不重叠。

因此,查询计划员可能应该选择全表扫描来代替您的条件。在MySQL中,查询规划人员不擅长使用多个索引的情况尤其如此。

您可以或不可以通过(low, high, s)上的复合索引加速此确切查询 - 原始列名为(Col_1, Col_2, MyString)。这被称为covering index,并允许MySQL完全从索引中满足查询。它有时有助于表现。 (如果您的表格的确切定义可用,那么猜测这是否会有所帮助;覆盖索引的效率取决于其他索引,主键,列大小等内容,但您已选择最少的公开内容)

这真的会有帮助吗?反思你的算法可以为你带来很多好处。您似乎试图检索测试点v位于[t.low,t.high]范围内的行。您的应用程序是否提供了范围宽度的先验限制?也就是说,有没有已知的最大值t.high - t.low?如果是这样,我们称之为maxrange。然后,你可以重写查询是这样的:

SELECT s 
    FROM t 
    WHERE t.low BETWEEN v-maxrange AND v 
    AND t.low <= v AND v <= t.high 

maxrange可用,我们可以添加col BETWEEN const1 AND const2条款。这将变成对low上索引的有效范围扫描。在那种情况下,上面提到的覆盖指数肯定会加速这个查询。

阅读此项。 http://use-the-index-luke.com/

+0

非常感谢@OllieJones或the详细的解释(以及花费的时间)!一些评论:1)我没有隐藏信息。该表格完全符合**的描述(两个BigInt列和前两列有索引的字符串); 2)不幸的是,最大和最小值之间没有预定义的范围(即't.high - t.low'); 3)测试值'v'是一个随机生成的数字。 – FDavidov

0

嗯......我找到了一个合适的解决方案(不确定你的家伙会喜欢它,但据说,它适用于我)。

我简单地分我的400K记录成多个表,并创建了一个简单的表用作选择器:

选择器表用一个简单的索引一起保持所述第一列的每个分区的极小值(即1,2,...)。

我那么用户下面来获取应该包含搜索到的范围,如表的索引:

SELECT Table_Index 
    FROM tbl_selector 
WHERE start_range <= Test_Val 
ORDER BY start_range DESC LIMIT 1 ; 

这会给我,我想从选择表的索引。

然后我在检索的索引上有一个CASE来选择正确的分区表来执行实际的搜索。 (我想更优雅的是使用动态SQL,但稍后会照顾;现在只是想测试方法)。

结果是我得到的响应远低于第二个(〜0.08),并且它是统一的,不管用于测试的数量。顺便说一句,以前的方法并不是这样:在那里,如果数字“接近”表的开头,则结果产生得相当快;另一方面,如果记录接近表格末尾,则需要几秒钟才能完成)。

[顺便说一句,我想你明白我的意思开始表结束]

同样,我敢肯定,人们可能不喜欢这一点,但它的工作对我来说。

谢谢大家的努力协助!