【问题标题】:indexes in mysql SELECT AS or using Viewsmysql SELECT AS 中的索引或使用视图
【发布时间】:2010-10-09 09:46:54
【问题描述】:

我对一个大型 mysql 查询 (mysql 5.0) 感到头疼,我希望这里有人可以提供帮助。

之前我问过如何从联合查询中获取不同的值 mysql count only for distinct values in joined query

我得到的响应(使用带有 join as 的子查询)

选择 * 来自媒体 m 内部联接 (选择uid 来自 users_tbl 限制 0,30) 地图 在 map.uid = m.uid 内连接 users_tbl u 在 u.uid = m.uid

不幸的是,我的查询变得越来越不守规矩,尽管我已经运行它,但加入派生表需要的时间太长,因为派生查询没有可用的索引。

我的查询现在看起来像这样

选择 mdate.bid, mdate.fid, mdate.date, mdate.time, mdate.title, mdate.name, mdate.address, mdate.rank, mdate.city, mdate.state, mdate.lat, mdate.`long`, 分机链接, ext.source、ext.pre、meta、mdate.img 从分机 右外连接( 选择 media.bid, media.date, media.time, media.title, users.name, users.img, users.rank, media.address, media.city, media.state, media.lat, media.`long`, GROUP_CONCAT(tags.tagname SEPARATOR ' | ') 作为元 来自媒体 在 media.bid = users.bid 上加入用户 LEFT JOIN tags ON users.bid=tags.bid 在 -122.52224684058 和 -121.79760915942 之间的“长” 和 37.07500915942 和 37.79964684058 之间的纬度 AND 日期 = '2009-02-23' GROUP BY media.bid, media.date ORDER BY media.date, users.rank DESC 限制 0, 30 ) mdate ON (mdate.bid = ext.bid AND mdate.date = ext.date)

呼!

所以,如您所见,如果我正确理解了我的问题,我有两个没有索引的派生表(我不否认我可能以某种方式搞砸了 Join 语句,但我一直在搞乱不同的类型,这是否最终给了我想要的结果)。

创建与此类似的查询的最佳方法是什么,这将使我能够利用索引? 我敢说,我实际上还有一张桌子可以在以后添加到组合中。

目前,我的查询需要 0.8 秒才能完成,但我确信如果我可以利用索引,这可能会明显更快。

【问题讨论】:

  • 在查看了 Quassnoi 使用 SPACIAL INDEX 的建议后,我意识到他们的索引中有一个错误,并且响应时间已大大缩短(现在为 0.1 秒)。但是,EXPLAIN 仍然指出我正在请求非索引列。

标签: mysql indexing derived-table


【解决方案1】:

首先,检查ext(bid, date)users(bid)tags(bid) 上的索引,你真的应该拥有它们。

不过,似乎是LONGLAT 给您带来了最多的问题。您应该尝试将您的LONGLAT 保留为(coordinate POINT),在此列上创建一个SPATIAL INDEX 并像这样查询:

WHERE MBRContains(@MySquare, coordinate)

如果由于某种原因您无法更改架构,您可以尝试创建包含 date 作为第一个字段的其他索引:

CREATE INDEX ix_date_long ON media (date, `long`)
CREATE INDEX ix_date_lat ON media (date, lat)

这些索引对于您的查询会更有效,因为您在 date 上使用精确搜索并在 axes 上使用范围搜索。

【讨论】:

  • 虽然我不否认 SPATIAL INDEX 的好处,但由于某种原因,我无法在我的数据库上创建一个(可能是因为我将 lat & long 分开存储。我将不得不调查但是,在这个过程中,我意识到我的 latlong 索引中有一个错误。查询时间现在是 0.1 秒。
  • 如果您想要 SPATIAL,您应该将坐标保留为特殊类型 GEOMETRY(在您的情况下为 POINT)。 LAT/LONG 索引确实有帮助的事实告诉我们你真的想要 SPATIAL :)
【解决方案2】:

重新开始:

问题 - 为什么要同时按 media.bid 和 media.date 进行分组?一个投标可以有多个日期的记录吗?

这是一个更简单的版本:

SELECT 
    mdate.bid,
    mdate.fid,
    mdate.date,
    mdate.time,
    mdate.title,
    mdate.name, 
    mdate.address,
    mdate.rank,
    mdate.city,
    mdate.state,
    mdate.lat,
    mdate.`long`,
    ext.link, 
    ext.source,
    ext.pre, 
    meta,
    mdate.img,
    (   SELECT GROUP_CONCAT(tags.tagname SEPARATOR ' | ')
        FROM tags 
        WHERE ext.bid = tags.bid
        ORDER BY tags.bid GROUP BY tags.bid
    ) AS meta

FROM 
    ext

LEFT JOIN
    media ON ext.bid = media.bid AND ext.date = media.date

JOIN
    users ON ext.bid = users.bid

WHERE 
    `long` BETWEEN -122.52224684058 AND -121.79760915942
    AND lat BETWEEN 37.07500915942 AND 37.79964684058
    AND ext.date = '2009-02-23'
    AND users.userid IN
    (    
        SELECT userid FROM users ORDER BY rank DESC LIMIT 30
    )

ORDER BY 
    media.date, 
    users.rank DESC
    LIMIT 0, 30

【讨论】:

  • 好吧,我没有对任何东西进行分组,我只是格式化了查询以便它可读:)
  • 感谢 le dorfier,我现在的工作做得很好,但是当我超过当前的截止日期时,我会尝试按照你的方式重新编写查询,看看我是否能做到这一点.它看起来确实更简单。
【解决方案3】:

您可能希望将您的性能与对每个选择使用临时表进行比较,然后将这些表连接在一起。

创建表#whatever 创建表 #whatever2

插入#whatever select... 插入 #whatever2 选择...

从#whatever 中选择加入#whatever 2

....

删除表#whatever 删除表 #whatever2

如果您的系统有足够的内存来保存完整的表,这可能会更快。这取决于您的数据库有多大。

【讨论】:

    猜你喜欢
    • 2011-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-27
    • 1970-01-01
    • 2016-02-13
    相关资源
    最近更新 更多