简化慢速MySQL查询

时间:2018-09-12 10:02:14

标签: mysql

此查询根据子查询中的COUNT列计算列freeplusscoretotal

SELECT movie_title,movie_id,MAX(x.free_cnt) as free, MAX(x.plus_cnt) as plus, 
                (MAX(x.free_cnt) + (MAX(x.plus_cnt)*3)) AS score, (MAX(x.free_cnt) + MAX(x.plus_cnt)) AS total
                    FROM (
                        SELECT b.id as movie_id, b.movie_title as movie_title, COUNT(*) AS free_cnt, 0 as plus_cnt
                        FROM subtitles_request a1
                        LEFT JOIN movies b on a1.movie_id=b.id
                        JOIN users c on c.email=a1.email
                        WHERE c.subsc_status='0'
                        GROUP BY b.movie_title
                        UNION ALL

                        SELECT d.id as movie_id, d.movie_title as movie_title,  0 as free_cnt, COUNT(*) AS plus_cnt
                        FROM subtitles_request a2
                        LEFT JOIN movies d on a2.movie_id=d.id
                        JOIN users e on e.email=a2.email
                        WHERE e.subsc_status='1'
                        GROUP BY d.movie_title

                    ) AS x
                    GROUP BY movie_title
                    ORDER BY total DESC
                    LIMIT 10

执行速度很慢,我想知道是否仍然可以简化或更改查询以提高性能。由于能够排序,我无法计算查询之外的freeplusscoretotal列。我也可以加入日期。

是否可以简化此查询?

2 个答案:

答案 0 :(得分:1)

尝试一下:

    SELECT b.movie_title, x.movie_id, MAX( x.free_cnt ) AS free, MAX( x.plus_cnt ) AS plus, 
           ( MAX( x.free_cnt ) + ( MAX( x.plus_cnt ) * 3 ) ) AS score, ( MAX( x.free_cnt ) + MAX( x.plus_cnt ) ) AS total
    FROM ( SELECT a.movie_id,
                  SUM( IF( c.subsc_status = '0', 1, 0 ) ) AS free_cnt, 
                  SUM( IF( c.subsc_status = '1', 1, 0 ) ) AS plus_cnt
           FROM subtitles_request a1
           JOIN users c on c.email=a1.email
           WHERE c.subsc_status in ('0','1')
           GROUP BY a.movie_id
         ) AS x
    LEFT JOIN movies b on x.movie_id = b.id
    GROUP BY movie_title, movie_id
    ORDER BY total DESC
    LIMIT 10

也许我简化了太多。此外,我不习惯仅对一些非聚合字段进行分组,因此我在要分组的内容上添加了movie_id,从而稍微更改了您的查询(如果两部电影的名称相同,但ID不同,则您原来的查询中只会返回一个ID,但是我猜(我是MySQL的新手,我真的不知道)这两个ID的计数是合计的。

HTH, 设置

答案 1 :(得分:0)

好吧,我已经检查了您的子查询:

(defstruct comment style string)
(defstruct whitespace string)

(defconstant +whitespace-chars+ '(#\Space #\Tab #\Return #\Newline))
(defconstant +eof+ (gensym "EOF"))

(defun read-semicolon-comment (stream semicolon)
  (declare (ignore semicolon))
  (make-comment :style :semicolon :string
    (with-output-to-string (comment)
      (loop (let ((char (read-char stream nil +eof+ t)))
              (cond ((equal char +eof+) (return))
                ((equal char #\Newline)
                  (unread-char char stream)
                  (return))
                (t (write-char char comment))))))))

(defun read-whitespace (stream first-char)
  (make-whitespace :string
    (with-output-to-string (whitespace)
      (write-char first-char whitespace)
      (loop (let ((char (read-char stream nil +eof+ t)))
              (unless (member char +whitespace-chars+)
                (unless (equal char +eof+) (unread-char char stream))
                (return))
              (write-char char whitespace))))))

(defun read-stream (stream)
  (with-standard-io-syntax ; Here's a comment, for example.
    (let ((*readtable* (copy-readtable)))
      (set-macro-character #\; #'read-semicolon-comment)
      (dolist (char +whitespace-chars+)
        (set-macro-character char #'read-whitespace))
      (loop for x = (read stream nil +eof+) until (equal x +eof+)
        collect x))))

(defmethod print-object ((x comment) stream)
  (assert (equal :semicolon (comment-style x)))
  (write-char #\; stream)
  (write-string (comment-string x) stream)
  x)

(defmethod print-object ((x whitespace) stream)
  (write-string (whitespace-string x) stream)
  x)

(mapc #'prin1 (read-stream *standard-input*))

“ UNION ALL”旁边的语句可以替换为条件为SELECT b.id as movie_id, b.movie_title as movie_title, COUNT(*) AS free_cnt, 0 as plus_cnt FROM subtitles_request a1 LEFT JOIN movies b on a1.movie_id=b.id JOIN users c on c.email=a1.email WHERE c.subsc_status='0' GROUP BY b.movie_title UNION ALL SELECT d.id as movie_id, d.movie_title as movie_title, 0 as free_cnt, COUNT(*) AS plus_cnt FROM subtitles_request a2 LEFT JOIN movies d on a2.movie_id=d.id JOIN users e on e.email=a2.email WHERE e.subsc_status='1' GROUP BY d.movie_title 的一条语句。您可以尝试在c.subsc_status IN('0','1')上使用“ CASE WHEN”语句,就像0 as free_cnt, COUNT(*) AS plus_cnt一样。这不是复杂的sql语句,我认为查询不会花费太多时间。数据太多了吗? 事实上,我也是新手,但是我对此有一些了解。如果它不起作用,请原谅我。