mysql - 通过合并的 LEFT JOIN 过滤
问题描述
我有一个我正在尝试优化的 MySQL 查询,这与权限有关。这是一个简化版本:
SELECT COUNT(*) FROM photo
LEFT JOIN photo_access ON viewer=4 AND owner=photo.photographer
WHERE
photo.album = 10
AND NOT photo.hidden
AND COALESCE(photo_access.access, 3) >= photo.privacy; -- 3=default access
出于我们的目的,这是我们关心的每个表的列。
photo.photographer : User ID of who took the photo
photo.album : Album ID (photo can only belong to one album)
photo.hidden : Tombstone value for photos that were removed by moderators
photo.privacy : Int, higher values = more restricted, 1=public 8=just_me
photo_access.viewer : Who is making the web request
photo_access.owner : Who owns the content
photo_access.access : Value like photo.privacy
大多数用户对其他用户的内容具有默认访问级别 (3)。我们将与默认值的偏差(由于友谊或阻止人等)存储在photo_access
表中。对于给定的一对查看者和内容所有者,您可以将其视为对 access=3 默认值的覆盖。
现在假设有几百万用户。实际存储所有可能的配对将是 N 2行,这有点疯狂。为简单起见,我考虑存储默认对,但在这种规模下这是不合理的。
对于某些值和情况,此设置效果很好。但是要抛出一些比例数字,为了得到与查询优化器的基数估计器相同的脑波,假设有:
- 数据库中有500张专辑,
- 总共100万张照片,
- 一个相当大的相册(id=10)中的 80K 张照片,
- 其中,70K 拥有
NOT photo.hidden
.
就我的直觉而言,我认为首先过滤专辑/隐藏,然后过滤隐私是有意义的。但是当我EXPLAIN
查询时,它:
- 在 上使用
(album, hidden, photographer)
索引photo
, - 仅使用前两个字段(忽略摄影师),如
const, const
, - 但估计它必须查看 150K 行!这几乎是相册大小的两倍,并且是可见照片的两倍多——考虑到正在使用的索引,我希望这里接近 70K。
- Extra 列为 NULL。通常不是一个好兆头。
而且这个查询不是异步报告。它运行大约 0.50 秒,而它应该在 0.01-0.06 秒范围内运行。这也让我对构建临时表保持警惕。
我在这里缺少什么吗?这些过滤条件(相册与基于摄影师的 photo_access 连接)是否具有不可能的交叉用途?即使是(准确的!)标记为重复项也会为我指明正确的方向。
解决方案
也许将您的选择拆分为两个选择的联合可能会有所帮助?像这样的东西。
SELECT COUNT(*) FROM
(SELECT 1 as `dummy` FROM photo
INNER JOIN photo_access ON viewer=4 AND owner=photo.photographer
WHERE
photo.album = 10
AND NOT photo.hidden
AND photo_access.access >= photo.privacy
UNION ALL
SELECT 1 as `dummy` FROM photo
LEFT JOIN photo_access ON viewer=4 AND owner=photo.photographer
WHERE
photo.album = 10
AND NOT photo.hidden
AND photo_access.access is null)
推荐阅读
- javascript - 如何在 JavaScript 中做一个 8 位、16 位和 32 位线性反馈移位寄存器 PRNG?
- angular - 如何从不在 setFilter、setPaging、setSort 上的用户输入获取 ng2-smart-table 事件的更改
- javascript - 如何在异步函数中从此返回的对象中提取数据?
- python - 如何检查列表中每个元组的第一个元素是否是字典的键?
- javascript - 错误:超过最大更新深度。componentWillUpdate 或 componentDidUpdate。React 限制嵌套更新的数量以防止无限循环
- python - 在 postgresql 查询中传递列和值列表
- actions-on-google - 无法将用户添加到 Alpha 测试
- python - 当这个问题出现时,如果我想继续我的代码怎么办?RuntimeError:未找到最佳参数
- django - 如何在 DRF 中创建多个实例?
- python - 如何使用 python 从 Cardinal Scale 头的串口读取序列值?