我目前在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的第一篇文章,我希望我没有搞砸任何东西!
提前致谢!
从Strawberry的评论中,我有了创建一个新表的想法,该表只包含两列,即id(主键,上面的表结构中未显示)和缩短的标签列,只有第一列等效记录的BigTag列的5个字符。然后我可以添加一个触发器来添加或删除此表中的记录以匹配原始PropData表。如果效果很好并且没有其他解决方案仅适用于现有表格,我会回发回来。
所以我尝试了我在上面段落中所说的内容,并且得到了一些非常奇怪的结果。在创建一个名为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决定突然使用不同的索引?
有没有人有任何想法或意见?