Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
强制MySQL使用非包容性索引以避免表扫描?_Mysql_Indexing - Fatal编程技术网

强制MySQL使用非包容性索引以避免表扫描?

强制MySQL使用非包容性索引以避免表扫描?,mysql,indexing,Mysql,Indexing,背景: 具有字段ID自动递增主键和另一列时间戳的大型表,该列时间戳存储行插入操作时的UNIX时间戳。时间戳列不在任何索引中,由于性能原因,我无法对其进行索引 情况:我们需要在这个巨大的表中查询特定时间戳值之前的过去行;我们可以发出一个SELECT语句,并在WHERE子句中指定该条件,但这将导致全表扫描,因为时间戳列没有索引 建议:这两列的性质都是随着插入的每一行而递增的:自动递增列和时间戳列也会增加。我可以每次将表划分为两个相等数量的行,并检查每个边界处的时间戳,依此类推,直到到达一行,然后使用

背景: 具有字段ID自动递增主键和另一列时间戳的大型表,该列时间戳存储行插入操作时的UNIX时间戳。时间戳列不在任何索引中,由于性能原因,我无法对其进行索引

情况:我们需要在这个巨大的表中查询特定时间戳值之前的过去行;我们可以发出一个
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范围 检查大表的索引
因此,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根据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
的命令并重新发布