可以对索引列执行二进制搜索以从非索引列获取数据吗?

zpgglvta  于 2021-07-24  发布在  Java
关注(0)|答案(1)|浏览(213)

我有一张大table users(id, inserttime, ...) ,仅启用索引 id . 我想找到在给定的 start_date 以及 finish_date 射程。 User.where(inserttime: start_date..finish_date).find_each ^这会导致搜索过程花费大量时间,因为 inserttime 列未编入索引。
我想出的解决办法是 user.id 为了 start_date 以及 finish_date 分别使用索引的 id 列。
然后这样做让所有的用户 start_id 以及 finish_id : User.where(id: start_id..finish_id).find_each 我使用的二进制搜索函数是这样的:

def find_user_id_by_date(date)
    low = User.select(:id, :inserttime).first
    high = User.select(:id, :inserttime).last

    low_id = low.id
    high_id = high.id

    low_date = low.inserttime
    high_date = high.inserttime

    while(low_id <= high_id)
        mid_id = low_id + ((high_id - low_id) / 2);
        mid = User.select(:id, :inserttime).find_by(id: mid_id)

        # sometimes there can be missing users. Ex: [1,2,8,9,10,16,17,..]
        while mid.nil?
            mid_id = mid_id + 1
            mid = User.select(:id, :inserttime).find_by(id: mid_id)
        end

        if (mid.inserttime < date)
            low_id = mid.id + 1
        elsif (mid.inserttime > date)
            high_id = mid.id - 1
        else
            return mid.id
        end
    end

    # when date = start_date
    return (low_id < high_id) ? low_id + 1 : high_id + 1

    # when date = finish_date
    return (low_id < high_id) ? low_id : high_id + 1
end

我不确定我所做的是不是正确的方法来处理这个问题,甚至我的二进制搜索功能是否涵盖了所有的情况。
我认为最好的解决办法是在 inserttime 但遗憾的是,这是不可能的。

f0brbegy

f0brbegy1#

这可能不是最好的方法,但是如果id是数字的并且是连续的,您可以编写一个查询来查找介于最小和最大用户id之间的用户:

SELECT id
FROM users
WHERE id BETWEEN [low_id_here] AND [high_id_here];

在activerecord中:

low = User.select(:id, :inserttime).first
high = User.select(:id, :inserttime).last

low_id = low.id
high_id = high.id

User.where('id BETWEEN ? AND ?', low_id, high_id)

相关问题