强制MySQL使用非包容性索引以避免表扫描?
背景: 具有字段ID自动递增主键和另一列时间戳的大型表,该列时间戳存储行插入操作时的UNIX时间戳。时间戳列不在任何索引中,由于性能原因,我无法对其进行索引 情况:我们需要在这个巨大的表中查询特定时间戳值之前的过去行;我们可以发出一个强制MySQL使用非包容性索引以避免表扫描?,mysql,indexing,Mysql,Indexing,背景: 具有字段ID自动递增主键和另一列时间戳的大型表,该列时间戳存储行插入操作时的UNIX时间戳。时间戳列不在任何索引中,由于性能原因,我无法对其进行索引 情况:我们需要在这个巨大的表中查询特定时间戳值之前的过去行;我们可以发出一个SELECT语句,并在WHERE子句中指定该条件,但这将导致全表扫描,因为时间戳列没有索引 建议:这两列的性质都是随着插入的每一行而递增的:自动递增列和时间戳列也会增加。我可以每次将表划分为两个相等数量的行,并检查每个边界处的时间戳,依此类推,直到到达一行,然后使用
SELECT
语句,并在WHERE
子句中指定该条件,但这将导致全表扫描,因为时间戳列没有索引
建议:这两列的性质都是随着插入的每一行而递增的:自动递增列和时间戳列也会增加。我可以每次将表划分为两个相等数量的行,并检查每个边界处的时间戳,依此类推,直到到达一行,然后使用该ID对其运行一个正常的SELECT
此解决方案的问题:它很难,需要大约25个查询才能完成该操作,并且随着表的增长,查询数量会增加
所以问题是:是否可以指示MySQL在原子上下文中执行该操作?我会尝试为主表构建一个辅助表,至少作为查询的限制基础。在桌子上涂上类似。。。(很明显,按日期基准放置Index) 然后,您可以预查询该表,以获得查询中的最小PK(如果查找日期范围,则可能是最大PK)。为了在不必重新构建的情况下保持它,我会在主表中添加一个触发器,如果尚未插入日期,则尝试插入DailyStartKey表 这样的查询利用这可能是
select
YourTable.*
from
( select FirstPKForDay
from DailyStartKey
where DateBasis = "2011-02-12" ) StartDate,
( select FirstPKForDay
from DailyStartKey
where DateBasis = "2011-02-25" ) LastDate,
YourTable
where
YourTable.YourAutoIncColumn >= StartDate.FirstPKForDay
and YourTable.YourAutoIncColumn <= LastDate.FirstPKForDay
如果已经找到一个,请忽略。。否则,触发器应该插入daily key表并更新“LastDateEntryTable”。我会尝试为主表构建一个辅助表,至少作为查询的限制基础。在桌子上涂上类似。。。(很明显,按日期基准放置Index) 然后,您可以预查询该表,以获得查询中的最小PK(如果查找日期范围,则可能是最大PK)。为了在不必重新构建的情况下保持它,我会在主表中添加一个触发器,如果尚未插入日期,则尝试插入DailyStartKey表 这样的查询利用这可能是
select
YourTable.*
from
( select FirstPKForDay
from DailyStartKey
where DateBasis = "2011-02-12" ) StartDate,
( select FirstPKForDay
from DailyStartKey
where DateBasis = "2011-02-25" ) LastDate,
YourTable
where
YourTable.YourAutoIncColumn >= StartDate.FirstPKForDay
and YourTable.YourAutoIncColumn <= LastDate.FirstPKForDay
如果已经找到一个,请忽略。。否则,触发器应该插入每日键表并更新“LastDateEntryTable”。您考虑过根据日期范围对表进行分区吗?如果查询中有日期范围&表是分区的,则可以避免对整个表进行扫描。您还可以对索引进行分区
您是否考虑过根据日期范围对表进行分区?如果查询中有日期范围&表是分区的,则可以避免对整个表进行扫描。您还可以对索引进行分区
即兴发挥Drapp的创意:创建一个帮助表和一个触发器,在这个表中每100行添加一行。此表将等效于以下视图,但它将有一个基于DateTimeBase的索引
CREATE VIEW HundredRowsStartKey AS
SELECT
YourTimeStampColumn AS datetimeBasis,
YourAutoIncColumn AS id
FROM
YourTable
WHERE
YourAutoIncColumn % 100 = 0
;
还增加了对最终查询详细信息的改进,因此它最多对大表的200行进行datetime扫描。使用索引获取所有其他匹配行和所需的中间数据:
- 在帮助表上进行2次搜索 (百度起步)和
- 3范围 检查大表的索引
SELECT *
FROM
YourTable
WHERE
YourTimeStampColumn BETWEEN "2011-02-12-01.00.23"
AND "2011-03-15-12.00.00"
;
将成为:
WITH starting AS
SELECT
max(id) AS startLow
FROM
HundredRowsStartKey h
WHERE datetimeBasis <= "2011-02-12-01.00.23"
;
WITH ending AS
SELECT
max(id) AS endLow
FROM
HundredRowsStartKey h
WHERE datetimeBasis <= "2011-03-15-12.00.00"
;
SELECT *
FROM
YourTable
WHERE
-- these are guaranteed
( YourAutoIncColumn >= starting.startLow+100
AND YourAutoIncColumn <= ending.endLow-1
)
-- and these 200 we have to filter
OR
( ( YourAutoIncColumn BETWEEN starting.startLow
AND starting.startLow+99
OR
YourAutoIncColumn BETWEEN ending.endLow
AND ending.endLow+99
)
-- with the original filter
AND
( YourTimeStampColumn BETWEEN "2011-02-12-01.00.23"
AND "2011-03-15-12.00.00"
)
)
;
以
选择
马克斯(身份证)为斯达洛
从…起
百度星基h
其中datetimeBasis根据Drapp的想法即兴创作:创建一个帮助表和一个触发器,在这个表中每100行添加一行。此表将等效于以下视图,但它将有一个基于DateTimeBase的索引
CREATE VIEW HundredRowsStartKey AS
SELECT
YourTimeStampColumn AS datetimeBasis,
YourAutoIncColumn AS id
FROM
YourTable
WHERE
YourAutoIncColumn % 100 = 0
;
还增加了对最终查询详细信息的改进,因此它最多对大表的200行进行datetime扫描。使用索引获取所有其他匹配行和所需的中间数据:
- 在帮助表上进行2次搜索
(百度起步)和
- 3范围
检查大表的索引
因此,datetime范围查询:
SELECT *
FROM
YourTable
WHERE
YourTimeStampColumn BETWEEN "2011-02-12-01.00.23"
AND "2011-03-15-12.00.00"
;
将成为:
WITH starting AS
SELECT
max(id) AS startLow
FROM
HundredRowsStartKey h
WHERE datetimeBasis <= "2011-02-12-01.00.23"
;
WITH ending AS
SELECT
max(id) AS endLow
FROM
HundredRowsStartKey h
WHERE datetimeBasis <= "2011-03-15-12.00.00"
;
SELECT *
FROM
YourTable
WHERE
-- these are guaranteed
( YourAutoIncColumn >= starting.startLow+100
AND YourAutoIncColumn <= ending.endLow-1
)
-- and these 200 we have to filter
OR
( ( YourAutoIncColumn BETWEEN starting.startLow
AND starting.startLow+99
OR
YourAutoIncColumn BETWEEN ending.endLow
AND ending.endLow+99
)
-- with the original filter
AND
( YourTimeStampColumn BETWEEN "2011-02-12-01.00.23"
AND "2011-03-15-12.00.00"
)
)
;
以
选择
马克斯(身份证)为斯达洛
从…起
百度星基h
其中datetimeBasis很好,这就是BTREE索引的功能。表的行数和MB有多大?您是否实际测试了在时间戳列上添加索引的性能?当前行数为22M,我确实为该表的另一列创建了单列索引。这就是BTREE索引的功能。表的行和MB有多大?您是否实际测试了在时间戳列上添加索引的性能?当前行数为22M,我确实为该表的另一列创建了单列索引。+1因为我们不知道填充大表的速度,(每天100行?每分钟100行?)也许你甚至不知道这在将来会发生多快:你可以让触发器在DailyStartKey中为在大表中添加的每一个C(比如100)行添加一行(这可能是1000或另一个常量)。这样,如果要搜索日期时间范围,只需先搜索(重命名的)HundredRowsStartKey,然后搜索大表中最多2C行即可。@DRapp:这是迄今为止最有可能接受的建议,不过每次插入时都需要查询表DailyStartKey
。Drapp你启发我运行一个CRON来表示新的一天:比如说通过一个文件系统令牌,每当找到它时,就会发出一个插入到DailyStartKey
的命令并重新发布