如何通过列

时间:2016-07-08 22:37:08

标签: mysql

我目前在MySQL InnoDB数据库中有两个表。以下是表格的两个简化版本。

表1(PropData):

+-----------------------------------+
|  PropData                         |
+-----------+-----------------------+
|  BigTag   |  Date                 |
+-----------+-----------------------+
|  10001AB  |  1000-01-01 00:00:00  |
+-----------+-----------------------+

表2(LimitTags):

+-------------------+
|  LimitTags        |
+---------+---------+
|  Tag    |  Model  |
+---------+---------+
|  10001  |  Base   |
+---------+---------+

用法:

PropData 表包含一堆我需要保存和绘制的数据,该表中的每条记录都有一个来自 LimitTags 表的某个标记/模型适用于它(即许多 PropData 记录可以引用一个 LimitTag 记录)。

目标:

我目前正在尝试创建查询,将通过在某个指定的时间跨度内搜索 PropData 表来检索唯一标记和模型对的列表,并确定哪些标记/模型对(来自LimitTags表)。

理想情况下,我认为通过从两个表中加入 Tag 字段,包括一个WHERE子句来获取我的时间跨度内的数据,然后选择不同的标签和模型,这是非常可行的。

障碍是 PropData 表中的标记还有两个字符 - 而不是 LimitTags 表中的等效标记 - 附加到它(因此名称为 BigTag ),这意味着我不能只是将这些表连在一起。

我尝试过的事情:

SELECT DISTINCT S.Tag, S.Model
FROM (
    SELECT  T.Tag, 
            T.Model,
            P.Date
    FROM (
        SELECT LEFT(BigTag, 5) AS Tag, Date
        FROM PropData
        GROUP BY LEFT(BigTag, 5)
    ) AS P
    JOIN LimitTags T ON T.Tag=P.Tag
) AS S
WHERE S.Date BETWEEN '1000-01-01 00:00:00' AND '9999-12-31 23:59:59'
ORDER BY S.Date DESC;

问题:

上述查询的问题在于,形成P的第一个子查询非常慢并且搜索整个表,这是数百万条记录。

运行explain命令通过告诉我查询正在使用filesort并且类型为ALL来确认这一点。

我基本上一直试图弄清楚如何从PropData中选择所有记录,其中我只采用BigTag列的前5个字符(以便轻松加入LimitTags)和日期(仅用于获取)我的时间跨度之间的数据,以及我只获得标签的前5个字符不同的记录(因此分组)。

我认为这个问题源于我在select和group by语句中使用Left()函数的方式(如下所示),但我还没弄清楚如何绕过它。

SELECT LEFT(BigTag, 5) AS Tag, Date
FROM PropData
GROUP BY LEFT(BigTag, 5)

我也为PropData提供了一个索引(BigTag)和(BigTag(5),Date),但是在P的查询中都没有使用这两个索引。在LimitTags的Tag上还有一个索引,在索引期间使用加入操作。

我对MySQL很新,并且总体上编写查询,并且绝对可以使用一些有关如何实现此目的的建议。这也是我关于SO的第一篇文章,我希望我没有搞砸任何东西!

提前致谢!

编辑1:

从Strawberry的评论中,我有了创建一个新表的想法,该表只包含两列,即id(主键,上面的表结构中未显示)和缩短的标签列,只有第一列等效记录的BigTag列的5个字符。然后我可以添加一个触发器来添加或删除此表中的记录以匹配原始PropData表。如果效果很好并且没有其他解决方案仅适用于现有表格,我会回发回来。

编辑2:

所以我尝试了我在上面段落中所说的内容,并且得到了一些非常奇怪的结果。在创建一个名为PropDataTag的新表之后,其中列是Id,而PropData是BigTag的前5个字符。我尝试过执行此查询:

SELECT DISTINCT T.Tag, T.Model
FROM PropData P
   JOIN PropDataTag N ON P.Id=N.Id
      JOIN LimitTags T ON N.Tag=T.Tag
WHERE P.Date BETWEEN '0000-01-01 00:00:00' AND '9999-12-31 23:59:59'

我第一次跑它,它完美无缺,我得到的结果是0.016秒。我还运行了explain命令并得到了以下结果。当我拍摄屏幕截图时,我遗憾地忽略了扩展参考列,因此我不知道其中的两个值是什么,并且无法再现这些结果。

id  select_type  table  type    possible_keys                 key             key_len   ref     rows     Extra 
1   SIMPLE       T      index   IdxTag,IdxTagAndModel         IdxTagAndModel  49        NULL    1427     Using index; Using temporary
1   SIMPLE       N      ref     IdxTag                        IdxTag          7         NoIdea  1238     Using index; Distinct
1   SIMPLE       P      eq_ref  PRIMARY,IdxDate,IdxIdAndDate  IdxDate         38        NoIdea  1        Using where; Distinct

认为一切都很好,然后我在其他3个PropData表(在评论中提到)上尝试完全相同的查询并将它们联合起来。在运行查询之后,我花了超过2分钟才停止了太长时间。我尝试在上面显示的原始查询上运行explain命令,而不是得到相同的结果,我得到以下内容:

id  select_type  table  type    possible_keys                 key         key_len   ref    rows     Extra 
1   SIMPLE       P      range   PRIMARY,IdxDate,IdxIdAndDate  IdxDate     24        NULL   1785585  Using where; Using Index; Using temporary
1   SIMPLE       N      eq_ref  PRIMARY,IdxTag                PRIMARY     38        P.Id   1
1   SIMPLE       T      ref     IdxTag,IdxTagAndModel         IdxTag      7         N.Tag  1

刚刚发生了什么?我无法弄清楚:

  • 为什么解释输出中行的顺序会发生变化?

  • 为什么MySQL决定突然使用不同的索引?

有没有人有任何想法或意见?

0 个答案:

没有答案