复杂的 MySQL 查询问题和 SQL 挂起

Complex MySQL query problems and also SQL hangs

我正在尝试编写一个非常复杂的 SQL 查询。要求如下:

我需要 return 来自查询的这些字段:

track.artist
track.title
track.seconds
track.track_id
track.relative_file
album.image_file
album.album
album.album_id
track.track_number

我可以使用以下查询 select 随机曲目:

select 
  track.artist, track.title, track.seconds, track.track_id, 
  track.relative_file, album.image_file, album.album, 
  album.album_id, track.track_number 
FROM 
  track, album 
WHERE 
  album.album_id = track.album_id 
ORDER BY RAND() limit 10;

这就是我遇到问题的地方。我还有一个名为 "trackfilters1" 到 "trackfilters10" 的 table 每行都有一个自动递增的 ID 字段。因此,第 10 行是 album_id 10 的数据。这些字段填充有 1 和 0。例如,专辑 #10 有 10 首曲目,如果所有曲目都包含在搜索中,则 trackfilters1.flags 将包含“1111111111”。如果要排除轨道 10,则它将包含“1111111110”

我的问题是包括这个条款。

我提出的最新查询如下:

select 
  track.artist, track.title, track.seconds, 
  track.track_id, track.relative_file, album.image_file, 
  album.album, album.album_id, track.track_number 
FROM 
  track, album, trackfilters1, trackfilters2 
WHERE 
  album.album_id = track.album_id 
AND 
  ( (album.album_id = trackfilters1.id) 
OR 
    (album.album_id=trackfilters2.id) ) 
AND 
  ( (mid(trackfilters1.flags, track.track_number,1) = 1) 
OR 
  ( mid(trackfilters2.flags, track.track_number,1) = 1)) 
ORDER BY RAND() limit 2;

然而,这会导致 SQL 挂起。我假设我做错了什么。有人知道它是什么吗?如果有更简单的方法来实现我的最终结果,我会乐于接受建议,如果有更好的方法来完成此操作,我不会着手修复损坏的查询。

此外,在我的试验中,我注意到当我有一个工作查询并在 FROM 子句中添加 say trackfilters2 而没有在查询中的任何地方使用它时,它也会挂起。这让我想知道。这是正确的行为吗?我认为在不使用数据的情况下添加到 FROM 列表只会使服务器获取更多数据,我不会期望它挂起。

此处没有足够的信息来确定导致性能问题的原因。

但这里有一些建议和意见。

放弃连接操作的老式逗号语法,改用 JOIN 关键字。并将连接谓词重新定位到 ON 子句。

看在上帝的分上,格式化 SQL 以便试图阅读它的人能够破译它。

这里有一些问题...在 trackfilters1 和 trackfilters2 中是否总是有一个匹配的行与您想要 return 的行匹配?或者 trackfilters2 中可能缺少一行,如果 trackfilters1 中有匹配的行,您仍然想要 return 该行? (该问题的答案决定了您是要对这些表使用外部联接还是内部联接。)

为了在大型数据集上获得最佳性能,定义适当的索引至关重要。

使用EXPLAIN查看执行计划。

我建议您尝试这样编写查询:

  SELECT track.artist
       , track.title
       , track.seconds
       , track.track_id
       , track.relative_file
       , album.image_file
       , album.album
       , album.album_id
       , track.track_number
    FROM track
    JOIN album
      ON album.album_id = track.album_id
    LEFT
    JOIN trackfilters1
      ON trackfilters1.id = album.album_id
    LEFT
    JOIN trackfilters2
      ON trackfilters2.id = album.album_id
   WHERE MID(trackfilters1.flags, track.track_number, 1) = '1' 
      OR MID(trackfilters2.flags, track.track_number, 1) = '1'
   ORDER BY RAND()
   LIMIT 2

如果您需要性能方面的帮助,请提供 EXPLAIN 的输出以及定义的索引。