【问题标题】:How to improve an indexed inner join query Mysql?如何改进索引内连接查询 Mysql?
【发布时间】:2015-11-09 03:28:35
【问题描述】:

这是我在论坛上的第一个问题,所以如果我的问题有什么需要改进的地方,请随时告诉我。

我有一个有两个表的大数据库

  • “访问”(6M 行),基本上存储网站上的每次访问
|访问日期 |城市| ---------------------------------- | 2014-12-01 00:00:02 |巴黎 | | 2015-01-03 00:00:02 |马赛|
  • “cityweather”(1M 行)每天存储 3 次许多城市的天气信息
|天气预报 |城市| ---------------------------------- | 2014-12-01 09:00:02 |巴黎 | | 2014-12-01 09:00:02 |马赛|

我准确地说,表访问中可能有一些城市不在 cityweather 中,反之亦然,我只需要选择两个表共有的城市。

我首先有一个大查询,我尝试运行但失败了,因此我试图回到加入这两个表的最简单的查询,但性能很糟糕。

SELECT COUNT(DISTINCT(t.city)) 
FROM visit t 
INNER JOIN cityweather d
ON t.city = d.city;

我准确地说,这两个表都在列 city 上建立了索引,并且我已经在两个表上独立地执行了 COUNT(DISTINCT(city)),每个表只需要不到一秒钟的时间。

您可以在下面找到此查询的EXPLAIN 的结果:

|编号 |选择类型 |表|类型 |可能的键 |关键 | key_len |参考 |行 |额外 | ---------------------------------- | 1 |简单 | d |索引 | idx_city | idx_city | 303 |空 | 1190553 |使用哪里;使用索引 | | 1 |简单 |吨 |参考 |同城 |同城 | 303 | meteo.d.city |第465章使用索引 |

您将在表格信息下方找到这两个表格的引擎,尤其是两个表格的引擎:

访问

|姓名 |引擎 |版本 |行格式 |行 |平均行长度 |数据_len |最大数据长度 |索引_len |数据免费 | -------------------------------------------------- -------------------------------------------------- ---------------- |访问 |数据库 | 10 |紧凑 | 6208060 | 85 | 531628032 | 0 | 0 | 0 |

SHOW CREATE TABLE output

    CREATE TABLE
`visit` (
`productid` varchar(8) DEFAULT NULL,
`visitdate` datetime DEFAULT NULL,
`minute` int(2) DEFAULT NULL,
`hour` int(2) DEFAULT NULL,
`weekday` int(1) DEFAULT NULL,
`quotation` int(10) unsigned DEFAULT NULL,
`amount` int(10) unsigned DEFAULT NULL,
`city` varchar(100) DEFAULT NULL,
`weathertype` varchar(30) DEFAULT NULL,
`temp` int(11) DEFAULT NULL,
`pressure` int(11) DEFAULT NULL,
`humidity` int(11) DEFAULT NULL,
KEY `Idxvisitdate` (`visitdate`),
KEY `Idxcity` (`city`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

城市天气

|姓名 |引擎 |版本 |行格式 |行 |平均行长度 |数据_len |最大数据长度 |索引_len |数据免费 | -------------------------------------------------- -------------------------------------------------- -------------------------- |城市天气|数据库 | 10 |紧凑 | 1190553 | 73 | 877670784 | 0 | 0 | 30408704 |

SHOW CREATE TABLE output

CREATE TABLE `cityweather` (
`city` varchar(100) DEFAULT NULL,
`lat` decimal(13,9) DEFAULT NULL,
`lon` decimal(13,9) DEFAULT NULL,
`weatherdate` datetime DEFAULT NULL,
`temp` int(11) DEFAULT NULL,
`pressure` int(11) DEFAULT NULL,
`humidity` int(11) DEFAULT NULL,
KEY `Idxweatherdate` (`weatherdate`),
KEY `idx_city` (`city`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

我感觉问题来自type = indexref = NULL,但我不知道如何解决它...

You can find here a close question that did not help me solve my problem

谢谢!

【问题讨论】:

  • 您要解决的问题是什么?哪里/什么是错误?你能以表格的形式显示想要的结果吗?
  • 我的问题是查询持续了几个小时(我允许 60 000 秒)然后崩溃...... MyIsam 或 InnoDb 是什么意思?我对 Mysql 很陌生...
  • 如果查询中没有 WHERE 子句,你从哪里得到“使用 where;使用索引”? sqlfiddle.com/#!9/2d35d/3
  • 我更新了问题以添加每个表的状态。它们都是 InnoDb。
  • 我不知道为什么他们在其中...

标签: mysql join indexing query-performance


【解决方案1】:

您的查询太慢了,因为您使用的索引无法将行数减少到更快的数量。查看您的EXPLAIN 输出:它告诉您使用表cityweather 中的城市(idx_city)索引将需要1.190.553 行来处理。通过city 加入您的visit 表将再次需要该表中的465 行。

因此,您的数据库将不得不处理 1.190.553 x 465 行。

由于您的查询是您无法提高其性能。但是您可以修改您的查询,例如通过在您的访问数据上添加条件来缩小结果范围。尝试各种EXISTS 查询。

更新

也许这有帮助:

CREATE TEMPORARY TABLE tmpTbl 
SELECT distinct city as city from cityweather;

ALTER TABLE tmpTbl Add index adweerf (city);

SELECT COUNT(DISTINCT(city)) FROM visit WHERE city in (SELECT city from tmpTbl);

【讨论】:

  • 感谢 Benvorth,如果您将答案 SELECT * FROM visit 更改为 SELECT COUNT(DISTINCT(city)) FROM visit,我会将答案标记为已接受
  • 只用了 9 秒 :) 多亏了你,我想我开始了解如何设计高效的查询了!
【解决方案2】:

由于IN ( SELECT ... )优化不好,改

SELECT COUNT(DISTINCT(city)) FROM visit WHERE city in (SELECT city from tmpTbl);

SELECT COUNT(*)
    FROM ( SELECT DISTINCT city FROM cityweather ) x
    WHERE EXISTS( SELECT * FROM visit
                   WHERE city = x.city );

两个表都需要(并且拥有)city 上的索引。我很确定最好将较小的表(cityweather)放在SELECT DISTINCT 中。

其他要点:

  • 每个 InnoDB 表都应该有一个 PRIMARY KEY
  • 您可以通过使用TINYINT UNSIGNED(1 字节)等来节省大量空间,而不是始终使用 4 字节 INT。
  • 9 个小数位的 lat/lng 对于城市来说过多,需要 12 个字节。我投票支持 DECIMAL(4,2)/(5,2)(1.6km / 1mi 分辨率;5 字节)或 DECIMAL(6,4)/(7,4)(16m/52ft,7 字节)。

【讨论】:

  • 感谢您的反馈。第一次使用 gps 坐标 :) 我只是不明白您所说的 PRIMARY KEY 是什么意思,因为我的表中没有任何可能的 KEY ... 还是我误用了它?
  • (weatherdate, city) 的组合在整个cityweather 中是唯一的吗?如果是这样,您可以说 PRIMARY KEY(weatherdate, city) 并将索引放在 weatherdate 上。
猜你喜欢
  • 1970-01-01
  • 2021-12-20
  • 1970-01-01
  • 1970-01-01
  • 2012-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多