自己写:让它在两份索引里挑一份

👁️ 0 人浏览 💬 0 人评论 ❤️ 添加收藏

把下面的 TODO 补完:写一条同时给 price 和 cat 两个条件的查询,打出它挑了哪一份索引。

两张表
goods  400 行   id 主键|sup_id 1~20|cat 只有 A/B/C|price = i*7%500|name "g1"~"g400"
sup     20 行   id 主键|city 杭州/苏州/南京/合肥(杭州 5 家)|name "s1"~"s20"

五个现成的工具函数(题面里已经写好)
plan(sql)      → 执行计划的每一行(一条查询可能有好几行)
first(sql)     → 只取第一行的第一个词:SCAN 还是 SEARCH
sortstep(sql)  → 有没有为排序/分组额外搭架子;有的话是为了哪一句
usedindex(sql) → 计划第一行用上的是哪一份索引
counted(sql)   → 数出这条查询把条件判了多少次(条件里要放 tick())
import sqlite3
db = sqlite3.connect(":memory:")
db.execute("CREATE TABLE sup (id INTEGER PRIMARY KEY, city TEXT NOT NULL, "
           "name TEXT NOT NULL)")
db.execute("CREATE TABLE goods (id INTEGER PRIMARY KEY, sup_id INTEGER NOT NULL, "
           "cat TEXT NOT NULL, price INTEGER NOT NULL, name TEXT NOT NULL)")
CITY = ["杭州", "苏州", "南京", "合肥"]
db.executemany("INSERT INTO sup VALUES (?,?,?)",
               [(i, CITY[i % 4], "s" + str(i)) for i in range(1, 21)])
db.executemany("INSERT INTO goods VALUES (?,?,?,?,?)",
               [(i, i % 20 + 1, "ABC"[i % 3], i * 7 % 500, "g" + str(i))
                for i in range(1, 401)])
db.commit()

def plan(sql):
    """把执行计划一行一行打出来(每行开头那个词就是取数方式)。"""
    return [r[3] for r in db.execute("EXPLAIN QUERY PLAN " + sql)]

def first(sql):
    """只要计划第一行的第一个词:SCAN(扫过去)还是 SEARCH(定点找)。"""
    return plan(sql)[0].split()[0]

def sortstep(sql):
    """有没有为了排序/分组**额外搭一次架子**?有的话是为了哪一句。"""
    for line in plan(sql):
        if "TEMP B-TREE" in line:
            return line.split("FOR ")[1].replace(" ", "")
    return "没有"

def usedindex(sql):
    """计划第一行用上的是哪一份索引(没用上就是"没有")。"""
    head = plan(sql)[0]
    if "INDEX " not in head:
        return "没有"
    return head.split("INDEX ")[1].split(" ")[0]

def counted(sql):
    """数一数这条查询把条件判了多少次。
    ⚠️ tick() 必须写在条件的最前面:写在后面时它只对已经匹配上的行求值,
       数出来的就变成"结果有几行",而不是"过了几行"。"""
    hits = {"n": 0}
    db.create_function("tick", 0, lambda: hits.__setitem__("n", hits["n"] + 1) or 1)
    db.execute(sql).fetchall()
    return hits["n"]
db.execute("CREATE INDEX ix_price ON goods(price)")
db.execute("CREATE INDEX ix_cat ON goods(cat)")
db.execute("CREATE INDEX ix_sup ON goods(sup_id)")
db.execute("CREATE INDEX ix_city ON sup(city)")
db.execute("ANALYZE")          # 攒一次统计,它才知道哪一列挑得更干净
q = ""   # TODO:写一条同时给 price = 7 和 cat = 'A' 两个条件的查询
print(usedindex(q))
提交你的答案
请登录后提交答案。
去登录
代码编辑器
Ctrl + Enter 运行
本次输入:
输出:

                        
👩‍🏫
AI
💬 题目评论

全部评论