Mysql 使用filesort&;简单地选择组;临时的,不是索引的

Mysql 使用filesort&;简单地选择组;临时的,不是索引的,mysql,sql,Mysql,Sql,所以我浏览了一下网络,似乎找不到答案。我有一张结构如下的桌子 Table structure for table `search_tags` -- CREATE TABLE IF NOT EXISTS `search_tags` ( `ID` int(11) NOT NULL AUTO_INCREMENT, `LOOK_UP_TO_CAT_ID` int(11) NOT NULL, `SEARCH_TAG` text COLLATE utf8_unicode_520_ci NOT

所以我浏览了一下网络,似乎找不到答案。我有一张结构如下的桌子

Table structure for table `search_tags`
--

CREATE TABLE IF NOT EXISTS `search_tags` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `LOOK_UP_TO_CAT_ID` int(11) NOT NULL,
  `SEARCH_TAG` text COLLATE utf8_unicode_520_ci NOT NULL,
  `DATE` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `SOURCE` varchar(225) COLLATE utf8_unicode_520_ci NOT NULL,
  `SOURCE_ID` int(11) NOT NULL,
  `WEIGHT` int(11) NOT NULL DEFAULT '1000',
  PRIMARY KEY (`ID`),
  KEY `LOOK_UP_TO_CAT_ID` (`LOOK_UP_TO_CAT_ID`),
  KEY `WEIGHT` (`WEIGHT`),
  FULLTEXT KEY `SEARCH_TAG` (`SEARCH_TAG`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_520_ci AUTO_INCREMENT=1 ;
该表包含800000多行,并且正在增长

当我在
LOOK\u UP\u TO \u CAT\u ID
上使用group by运行查询时,运行查询需要1-2秒。我需要运行此基础的多个版本,并将其连接到其他表,但这似乎是瓶颈所在,因为向其中添加连接并不会降低速度

    SELECT LOOK_UP_TO_CAT_ID, WEIGHT
FROM  `search_tags` 
WHERE  `SEARCH_TAG` LIKE  '%metallica%'
GROUP BY  `LOOK_UP_TO_CAT_ID`
删除
groupby
会将查询时间降低到0.1,这似乎更容易接受,但随后我就得到了重复的查询时间

对groupby使用explain表明它正在创建一个临时表,而不是使用索引

+----+-------------+-------------+------+-------------------+------+---------+------+--------+----------------------------------------------+--+
| id | select_type |    table    | type |   possible_keys   | key  | key_len | ref  |  rows  |                    Extra                     |  |
+----+-------------+-------------+------+-------------------+------+---------+------+--------+----------------------------------------------+--+
|  1 | SIMPLE      | search_tags | ALL  | LOOK_UP_TO_CAT_ID | NULL | NULL    | NULL | 825087 | Using where; Using temporary; Using filesort |  |
+----+-------------+-------------+------+-------------------+------+---------+------+--------+----------------------------------------------+--+
所以我不确定mysql是否在这里做了正确的事情,但至少对我来说,不使用索引似乎是错误的。为什么要加快查询速度,最好的方法是什么

编辑:

以下是我的数据示例:

+----+-------------------+----------------------------------+------------+---------------+-----------+--------+
| ID | LOOK_UP_TO_CAT_ID |            SEARCH_TAG            |    DATE    |    SOURCE     | SOURCE_ID | WEIGHT |
+----+-------------------+----------------------------------+------------+---------------+-----------+--------+
|  1 |               521 | METALLICA                        | 2017-02-18 | artist        |        15 |      1 |
|  2 |               521 | METALLICA - NOTHING ELSE MATTERS | 2017-02-18 | tracklisting  |        22 |      2 |
|  3 |               522 | METALLICA                        | 2017-02-18 | artist        |        15 |      1 |
|  4 |               522 | METALLICA - ST. Anger            | 2017-02-18 | product_title |       522 |      2 |
+----+-------------------+----------------------------------+------------+---------------+-----------+--------+
期望结果

+-------------------+--------+
| LOOK_UP_TO_CAT_ID | WEIGHT |
+-------------------+--------+
|               521 |      1 |
|               522 |      1 |
+-------------------+--------+

在某种程度上,你的问题没有意义。您有一个全文索引,但使用的是像一样的
,它执行表格扫描。您需要使用
MATCH()
来使用全文索引

我真正认为正在发生的是返回的数据量很大。如果执行查询时没有按
排序或按分组,则会在生成结果时返回结果。您可以看到结果,因为早期扫描的某些行符合您的条件

分组依据
/
排序依据
需要读取所有结果

您可以通过执行
计数(*)
而不是
选择来检查这一点:

SELECT COUNT(*)
FROM `search_tags` 
WHERE `SEARCH_TAG` LIKE '%metallica%';
我怀疑这可能需要更长的时间

通过使用相关子查询,可以消除重复消除的性能影响:

SELECT st.LOOK_UP_TO_CAT_ID, st.WEIGHT
FROM `search_tags` st
WHERE `SEARCH_TAG` LIKE  '%metallica%' AND
      st.id = (SELECT MIN(st2.id) FROM search_tags st2 WHERE st2.LOOK_UP_TO_CAT_ID = st.LOOK_UP_TO_CAT_ID);
这特别需要在
search\u标签(查找到\u CAT\u ID,ID)
上建立索引以提高性能


但是,您可能还想使用
MATCH()
来利用全文索引。

给您一些建议

  • SEARCH\u像“%metallica%”这样的标签
    在这个不幸的世界里永远不会使用索引。类似于“%needle”
  • (前导
    %
    )的模式
    需要MySQL检查列中的每个值是否匹配<代码>干草堆,如“针%”
    (尾随
    %
    )不存在此问题

  • 您的
    SEARCH\u标签上有
    列,所以请使用它
    WHERE-MATCH('metallica')与SEARCH_标记
    是您需要的WHERE子句的形式

  • 表上有很多单列索引。这些方法通常无助于加快查询速度,除非它们恰好与您正试图执行的操作相匹配。您最好使用针对正在运行的查询而设计的

  • 您问题中的示例查询是

       SELECT LOOK_UP_TO_CAT_ID, WEIGHT
        FROM  search_tags 
       WHERE  SEARCH_TAG LIKE  '%metallica%'
    GROUP BY  LOOK_UP_TO_CAT_ID
    
    如果您将其更改为此,它将更有SQL意义,并且运行得更快

       SELECT  LOOK_UP_TO_CAT_ID, MAX(WEIGHT)
         FROM  search_tags 
        WHERE  SEARCH_TAG LIKE  'metallica%'
     GROUP BY  LOOK_UP_TO_CAT_ID
    
    (注意,我去掉了前面的
    %

    如果在
    上添加复合覆盖索引(搜索标记,查找类别ID,权重)
    此查询将变得非常快速。通过索引可以满足整个查询。MySQL随机访问索引以查找您的搜索标记,然后执行搜索以获得您请求的结果


    (旁白:当您在
    EXPLAIN
    中看到
    filesort
    groupby
    orderby
    查询中的输出时,不要担心。这是MySQL满足查询的一部分。
    filesort
    中的文件不一定意味着硬盘上的文件速度慢。)

    使用
    SELECT*
    groupby
    仅仅表明对SQL的理解很差。编辑您的问题并提供示例数据和所需结果。感谢您的解释。我采用了对抗法,因为这在我的情况下非常有效(从性能上看)。