如何在按另一列排序时按一列过滤?
Posted
技术标签:
【中文标题】如何在按另一列排序时按一列过滤?【英文标题】:How can I filter by one column whilst sorting by another? 【发布时间】:2014-11-12 10:09:25 【问题描述】:架构:
CREATE TABLE `Log` (
`EntryId` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`EntryTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP(),
`Severity` ENUM(
'LOG_LEVEL_CRITICAL',
'LOG_LEVEL_ERROR',
'LOG_LEVEL_WARNING',
'LOG_LEVEL_NOTICE',
'LOG_LEVEL_INFO',
'LOG_LEVEL_DEBUG'
) NOT NULL,
`User` TEXT,
`Text` TEXT NOT NULL,
PRIMARY KEY(`EntryId`),
KEY `EntryTime` (`EntryTime`)
) ENGINE=InnoDB COMMENT="Log of server activity";
查询:
SELECT
`EntryId`,
UNIX_TIMESTAMP(`EntryTime`) AS `EntryTime_UnixTS`
`Severity`,
`User`,
`Text`
FROM `Log`
ORDER BY `EntryTime` DESC, `EntryId` DESC
LIMIT 0, 20
根据观察和执行计划(尽管这需要在小型数据集上使用FORCE INDEX
!),索引正在按需要使用:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE Log index \N EntryTime 4 \N 20
现在我想添加一个范围条件:
WHERE `Severity` <= 'LOG_LEVEL_WARNING'
但我不知道如何选择一个键,这样这个简单的查询仍然可以使用索引,同时对一个列进行排序并在另一列上进行过滤。我想得越多,我的弱 SQL 直觉就越表明它甚至不可能使用当前形式的查询,尤其是因为条件在 范围 上。
你会如何处理这个问题?
【问题讨论】:
在Severity,EntryTime,EntryId
上创建一个新索引怎么样?
sqlfiddle.com/#!2/0d3397/1
@juergend:WHERE
会很慢,不是吗?您的新严重性指数未被使用
@OscarPérez:嗯,这似乎行得通。我不知道怎么做,尤其是因为我在this answer!
【参考方案1】:
在我看来,您需要创建一个包含三个必填字段的索引:
CREATE INDEX test_idx
ON Log (Severity,EntryTime,EntryId);
该服务器将能够使用此索引,因为它包含执行查询所需的所有内容。
【讨论】:
我在this answer 中被告知,索引上的尾随 PK 是错误的。为什么这里不一样?它似乎确实有效,但我无法概念化为什么会这样:(我的意思是,在范围条件下,无论如何它都必须进行一些排序,对吧?那么为什么结果如此之快:/跨度> 我从来没有读过...这是真的吗?你有没有找到任何官方的 mysql 页面说明这一点?据我所知,使用索引将帮助服务器以更快(对数?)的方式定位其范围内的所有记录...... 是的,我想即使查找不能保持不变,索引也会在很大程度上有所帮助;这将解释它。至于后面PK的事情,我不知道,这是我被告知的,并且该答案给出的解决方案有效。以上是关于如何在按另一列排序时按一列过滤?的主要内容,如果未能解决你的问题,请参考以下文章