查询缓存的实现

Implementation of QueryCache

除了直接匹配查询的空白规范化散列之类的东西之外,还有什么可能是一种有用的(但不一定是完美的)方式来以部分方式处理查询缓存?例如,让我们来看下面的基本情况:

SELECT
    Product,  # VARCHAR
    Revenue   # DOUBLE
FROM
    Sales
WHERE
    Country='US'

这可能被用作 'base-cache',可以在其上执行进一步的查询以潜在地提高性能:

SELECT
    Product,  # VARCHAR
    Revenue   # DOUBLE
FROM
    Sales
WHERE
    Country='US' AND State='CA'

因此,假设 from table(s) 中的数据不变,以下内容可作为确定缓存的起点:

但是,当我们考虑以下情况时,这就变得非常棘手了:

SELECT
    ProductGroup AS Product,  # Would produce a Product:VARCHAR hash
    Revenue   
FROM
    Sales
WHERE
    Country='US'

对于如何实现部分查询缓存,什么可能是一个现实的起点。


用例: 写入 SQL 以查询非 DBMS 管理的源中的数据,例如 CSV 文件,这将需要 ~20 秒左右的时间来发出任何查询,我们无法在文件上创建索引。 https://en.wikipedia.org/wiki/SQL/MED 或类似 Spark。

我认为以下内容可能是基本缓存实现的良好起点,它允许使用可以进一步查询以进行优化的缓存:

  1. 首先替换任何 udf 或 cte。查询本身需要是独立的。
  2. 标准化空格和大写。
  3. 散列整个查询。这将是我们的起点。
  4. 删除 select 字段并对查询的其余部分进行哈希处理。现在将所有单个项目的散列存储在 select 列表中。
  5. 对于部分缓存,生成一个散列减去select个字段,where,sort,limit+offset。 hash where's list(用AND分隔),确保缓存中不包含当前查询不包含的filter,orderby,看数据是否需要重新排序,limit+offset数,使得确保初始查询中的限制+偏移量为空或大于当前查询。

下面是数据保存方式的示例:

Hash 673c0185c6a580d51266e78608e8e9b2
HashMinusFields 41257d239fb19ec0ccf34c36eba1948e
HashOfFields [dc99e4006c8a77025c0407c1fdebeed3, …]
HashMinusFieldsWhereOrderLimit d50961b6ca0afe05120a0196a93726f5
HashOfWheres [0519669bae709d2efdc4dc8db2d171aa, ...]
HashOfOrder 81961d1ff6063ed9d7515a3cefb0c2a5
LimitOffset null

现在让我们尝试几个示例,我将使用人类可读的哈希值以便于阅读:

SELECT Name, Age FROM Sales WHERE id=2
-- fullHash:   selectname,agefromsaleswhereid=2
-- selectless: fromsaleswhereid=2
-- hashoffields: [name, age]
-- minusfieldswhereorderlimit: null
-- hashofwheres:  [id=2, ]
-- hashororder: null
-- limitoffset: null

-- query1
select age FROM sales where id=2
-- selectless: fromsaleswhereid=2
-- fields: [age] OK, all fields contained in initial fields

-- query2
select age FROM sales where id=2 and country='us' order by id limit 100 
-- minusfieldswhereorderlimit: null
-- hashofwheres: [id=2, country=us] OK initial query does not contain any additional filters
-- limitoffset: 100 OK initial limitoffset is null (infinity)
-- hashorder: orderbyid
--> Can grab partial cache, need to apply one filter and re-sort/limit:
    --> SELECT * FROM <cache> WHERE country='us' order by id limit 100

以上看起来是有效的初始实施吗?