我有一个看起来非常简单的查询。 但是,如果我将ORDER BY和LIMIT结合起来,则性能会逐级下降。 我发现了几个关于MySQL在大表中性能有限的问题,但我不认为这是原因所在,因为查询工作没有任何限制。
以下是关于增加“复杂性”的问题
SELECT * FROM `mydata`.`mytable` WHERE ((token='XFRA1NMDU9XY') AND (section=210874));
/* Rows: 0 Time: 0,094 sec. */
SELECT * FROM `mydata`.`mytable` WHERE ((token='XFRA1NMDU9XY') AND (section=210874)) LIMIT 1;
/* Rows: 0 Time: 0,063 sec. */
SELECT * FROM `mydata`.`mytable` WHERE ((token='XFRA1NMDU9XY') AND (section=210874)) ORDER BY mailing;
/* Rows: 0 Time: 0,125 sec. */
SELECT * FROM `mydata`.`mytable` WHERE ((token='XFRA1NMDU9XY') AND (section=210874)) ORDER BY mailing LIMIT 1;
/* Rows: 0 Time: 45,500 sec. */
注意最后一行查询时间的显著增加。 这并不是异常值,而是被复制了好几次。 实际上,这个查询的查询时间只有3分钟甚至更长,而其他的一切都很正常。
下面是一些数据:
节
(和其他)的索引,但没有令牌
表结构如下:
CREATE TABLE `mytable` (
`data` VARCHAR(32) NOT NULL COLLATE 'ascii_bin',
`mailing` INT(10,0) NOT NULL,
`token` VARCHAR(64) NULL DEFAULT NULL COLLATE 'ascii_bin',
`section` INT(10,0) NOT NULL,
`expiry` INT(10,0) NULL DEFAULT NULL,
PRIMARY KEY (`data`) USING BTREE,
INDEX `mailing_CS` (`mailing`) USING BTREE,
INDEX `section_CS` (`section`) USING BTREE,
CONSTRAINT `mailing_CS` FOREIGN KEY (`mailing`) REFERENCES `mydata`.`mailings` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE,
CONSTRAINT `section_CS` FOREIGN KEY (`section`) REFERENCES `mydata`.`sections` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
)
COLLATE='ascii_bin'
ENGINE=InnoDB
;
知道为什么ORDER BY和LIMIT 1的组合有这种效果吗? explain
告诉我,前一个查询(section_cs
)和最后一个查询(mailing_cs
)使用了不同的键(索引)。
当然,我可以不使用限制1
,因为每个令牌
将没有行,一行或几行。 但我想了解根本的问题。
MySQL ORDER BY with LIMIT是对大型数据集进行排序的交互式应用程序中ORDER BY最常用的用法。
确保它使用索引。 让ORDER BY with LIMIT在不扫描和排序完整结果集的情况下执行是非常重要的,因此它使用索引很重要--在这种情况下,一旦生成所需数量的行,就会启动索引范围扫描并停止查询执行。
例如,如果我确实选择了*FROM sites ORDER BY date_created DESC LIMIT 10; 我会在(date_created)上使用index来快速获得结果集。
现在,如果我有一些类似SELECT*FROM sites WHERE category_id=5 ORDER BY date_created DESC LIMIT 10;
在这种情况下,按date_created索引也可以工作,但它可能不是最有效的--如果它是一个罕见的类别,可能会扫描表的很大一部分以找到10行。 因此在(category_id,date_created)上建立索引将是一个更好的主意。
索引可能会帮助你!!
我认为MySQL试图在最后一次查询中使用mailing_cs
索引,而这个索引不是最佳的。
请尝试此查询:
SELECT *
FROM `mydata`.`mytable` USE INDEX (section_CS) IGNORE INDEX(mailing_CS)
WHERE (
(token = 'XFRA1NMDU9XY') AND
(section = 210874)
)
ORDER BY mailing
LIMIT 1
此外,您也可以对此表使用复合索引(节,邮寄)。
WHERE ((token='XFRA1NMDU9XY')
AND (section=210874))
ORDER BY mailing LIMIT 1;
需要以下组合索引中的任何一个:
INDEX(token, section, mailing)
INDEX(section, token, mailing)
应删除任何较短的索引(最左边的列匹配),以避免混淆。
至于你为什么有这些时间。。。
前两个--,其中a=1和b=2
-将使用索引(a)
或索引(b)
,但必须扫描以检查另一个值。 因此,即使切换到index(a,b)
或(b,a)
也会加快它们的速度。
对于第三个查询--,其中a=1和b=2按C
-是一个谜题; 应该比4号还要长。
order by
,没有合适的索引,需要以下内容:
限制1
)对于我的任何一个索引,第4个查询应该是毫秒级的。