【问题标题】:How to optimize this SQL query for a rectangular region?如何针对矩形区域优化此 SQL 查询?
【发布时间】:2010-04-12 22:04:11
【问题描述】:

我正在尝试优化以下查询,但我不清楚哪种索引或索引最好。我将瓷砖存储在二维平面中并查询该平面的矩形区域。就本问题而言,该表包含以下列:

  • id:主键整数
  • world_id: 一个整数外键,作为瓦片子集的命名空间
  • tileY:Y坐标整数
  • tileX:X坐标整数
  • value:此图块的内容,如果重要,则为 varchar。

我有以下索引:

  • “ywot_tile_pkey”主键,btree (id)
  • “ywot_tile_world_id_key”唯一,btree(world_id,“tileY”,“tileX”)
  • "ywot_tile_world_id" btree (world_id)

这是我要优化的查询:

ywot=> EXPLAIN ANALYZE SELECT * FROM "ywot_tile" WHERE ("world_id" = 27685  AND "tileY" <= 6  AND "tileX" <= 9  AND "tileX" >= -2  AND "tileY" >= -1 );                                                                    QUERY PLAN                                                                 -------------------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on ywot_tile  (cost=11384.13..149421.27 rows=65989 width=168) (actual time=79.646..80.075 rows=96 loops=1)
   Recheck Cond: ((world_id = 27685) AND ("tileY" <= 6) AND ("tileY" >= (-1)) AND ("tileX" <= 9) AND ("tileX" >= (-2)))
   ->  Bitmap Index Scan on ywot_tile_world_id_key  (cost=0.00..11367.63 rows=65989 width=0) (actual time=79.615..79.615 rows=125 loops=1)
         Index Cond: ((world_id = 27685) AND ("tileY" <= 6) AND ("tileY" >= (-1)) AND ("tileX" <= 9) AND ("tileX" >= (-2)))
 Total runtime: 80.194 ms

所以世界是固定的,我们正在查询一个矩形区域的瓷砖。一些可能相关的更多信息:

  • 查询区域的所有图块可能存在也可能不存在
  • 被查询的矩形的高度和宽度通常约为 10x10-20x20
  • 对于任何给定的 (world, X) 或 (world, Y) 对,可能有无限数量的匹配图块,但目前最坏的情况是大约 10,000 个,而且通常要少得多。
  • 新图块的创建频率远低于现有图块的更新频率(更改“值”),而且其本身的频率也远低于上述查询中的读取频率。

    我唯一能想到的就是在 (world, X) 和 (world, Y) 上建立索引。我的猜测是数据库将能够获取这两个集合并将它们相交。问题是对于其中任何一个,都有一个 可能 无限数量的匹配项。还有其他更合适的索引吗?

  • 【问题讨论】:

    • 每个图块都有唯一的整数 (x,y)。每个世界有多少像素?
    • 贾斯汀:可能无限。

    标签: sql postgresql indexing


    【解决方案1】:

    将表聚集在“ywot_tile_world_id_key”上,主键似乎只是一个人工 id。如果您有更多唯一的垂直值,而不是水平值,您可能想要颠倒顺序(world-id,y,x)。同时删除world-id上的唯一索引,它被复合索引复制。

    【讨论】:

    • AFAICT,集群会使我的网站宕机,并且必须定期重复,所以这不是一个理想的解决方案。
    • 我认为所有高变化表都需要定期进行重组。如果您知道您的增长率,您可以在数据页面中留下一个百分比,以允许更改(或延迟重组之间的时间)。
    【解决方案2】:

    X,Y 的 GIST 与 PostGIS 的大致相同。事实上,您甚至可以为 Postgresql 使用 PostGIS 扩展并获得相当大的收益

    【讨论】:

      【解决方案3】:

      这就是我最终要做的。查询现在约为 20 毫秒而不是 80 毫秒,这是一个不错的改进,但并不令人惊讶。

      1. 已加载 btree_gist 贡献模块
      2. 创建了以下索引:
        在 ywot_tile 上使用 gist (world_id, box(point("tileX","tileY"),point("tileX","tileY"))) 并发创建索引 ywot_tile_boxes;上一页>
        
      3. 将查询切换为如下所示:
        SELECT * FROM "ywot_tile" WHERE world_id = 27685 AND box(point("tileX","tileY"),point("tileX","tileY")) &&框(点(-2,-1),点(9,6));

      任何进一步的建议将不胜感激。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-08-03
        • 2021-05-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多