-3

我正在尝试优化查询,避免使用文件排序:

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;


DROP TABLE IF EXISTS `comment`;

CREATE TABLE `comment` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `thread_id` int(11) NOT NULL,
  `parent_id` int(11) DEFAULT NULL,
  `user_id` int(11) NOT NULL,
  `body` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `created_at` datetime NOT NULL,
  `state` int(11) NOT NULL,
  `abuse_count` int(11) DEFAULT NULL,
  `prediction_1` int(11) DEFAULT NULL,
  `prediction_2` int(11) DEFAULT NULL,
  `prediction_3` int(11) DEFAULT NULL,
  `prediction_4` int(11) DEFAULT NULL,
  `prediction_5` int(11) DEFAULT NULL,
  `prediction_6` int(11) DEFAULT NULL,
  `prediction_7` int(11) DEFAULT NULL,
  `prediction_8` int(11) DEFAULT NULL,
  `prono_concours` tinyint(1) DEFAULT NULL,
  `prono_points` double DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `IDX_9474526CE2904019` (`thread_id`),
  KEY `IDX_9474526C727ACA70` (`parent_id`),
  KEY `IDX_9474526CA76ED395` (`user_id`),
  KEY `IDX_PRONO` (`prono_concours`),
  KEY `IDX_CREATED_AT_STATE` (`created_at`,`state`),
  CONSTRAINT `FK_9474526C727ACA70` FOREIGN KEY (`parent_id`) REFERENCES `comment` (`id`),
  CONSTRAINT `FK_9474526CA76ED395` FOREIGN KEY (`user_id`) REFERENCES `customer_user` (`id`),
  CONSTRAINT `FK_9474526CE2904019` FOREIGN KEY (`thread_id`) REFERENCES `comment_thread` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

DROP TABLE IF EXISTS `comment_thread`;

CREATE TABLE `comment_thread` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `is_commentable` tinyint(1) NOT NULL,
  `num_comments` int(11) NOT NULL,
  `last_comment_at` datetime DEFAULT NULL,
  `site_id` int(11) NOT NULL,
  `content_id` int(11) NOT NULL,
  `content_type` int(11) NOT NULL,
  `race_date` datetime DEFAULT NULL,
  `num_race` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UNIQ_COMMENT_SITEID` (`site_id`,`content_id`,`content_type`),
  KEY `IDX_SITEID` (`site_id`),
  KEY `IDX_CONTENT` (`content_id`,`content_type`),
  KEY `IDX_COMMENTABLE` (`is_commentable`),
  KEY `IDX_LAST_COMMENT` (`last_comment_at`),
  KEY `IDX_CONTENT_TYPE` (`content_type`),
  KEY `IDX_RACEDATE` (`race_date`),
  KEY `IDX_NUMRACE` (`num_race`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


DROP TABLE IF EXISTS `customer_user`;

CREATE TABLE `customer_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `username_canonical` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `email_canonical` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `enabled` tinyint(1) NOT NULL,
  `salt` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `last_login` datetime DEFAULT NULL,
  `locked` tinyint(1) NOT NULL,
  `expired` tinyint(1) NOT NULL,
  `expires_at` datetime DEFAULT NULL,
  `confirmation_token` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `password_requested_at` datetime DEFAULT NULL,
  `roles` longtext COLLATE utf8_unicode_ci NOT NULL COMMENT '(DC2Type:array)',
  `credentials_expired` tinyint(1) NOT NULL,
  `credentials_expire_at` datetime DEFAULT NULL,
  `date_subscription` datetime NOT NULL,
  `last_login_ip` bigint(20) NOT NULL,
  `ref_client_le_turf` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UNIQ_D902723E92FC23A8` (`username_canonical`),
  UNIQUE KEY `UNIQ_D902723EA0D96FBF` (`email_canonical`),
  KEY `IDX_LAST_LOGIN_IP` (`last_login_ip`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;




/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

这是我要优化的查询(不要使用 Using Filesort,这似乎是由于 order by):

EXPLAIN 
SELECT c0_.id AS id0, c0_.body AS body1, c0_.created_at AS created_at2, c0_.state AS state3, c0_.abuse_count AS abuse_count4, c0_.prediction_1 AS prediction_15, c0_.prediction_2 AS prediction_26, c0_.prediction_3 AS prediction_37, c0_.prediction_4 AS prediction_48, c0_.prediction_5 AS prediction_59, c0_.prediction_6 AS prediction_610, c0_.prediction_7 AS prediction_711, c0_.prediction_8 AS prediction_812, c0_.prono_concours AS prono_concours13, c0_.prono_points AS prono_points14, c1_.id AS id15, c1_.is_commentable AS is_commentable16, c1_.num_comments AS num_comments17, c1_.last_comment_at AS last_comment_at18, c1_.site_id AS site_id19, c1_.content_id AS content_id20, c1_.content_type AS content_type21, c1_.race_date AS race_date22, c1_.num_race AS num_race23, c2_.username AS username24, c2_.username_canonical AS username_canonical25, c2_.email AS email26, c2_.email_canonical AS email_canonical27, c2_.enabled AS enabled28, c2_.salt AS salt29, c2_.password AS password30, c2_.last_login AS last_login31, c2_.locked AS locked32, c2_.expired AS expired33, c2_.expires_at AS expires_at34, c2_.confirmation_token AS confirmation_token35, c2_.password_requested_at AS password_requested_at36, c2_.roles AS roles37, c2_.credentials_expired AS credentials_expired38, c2_.credentials_expire_at AS credentials_expire_at39, c2_.id AS id40, c2_.date_subscription AS date_subscription41, c2_.last_login_ip AS last_login_ip42, c2_.ref_client_le_turf AS ref_client_le_turf43, c0_.thread_id AS thread_id44, c0_.parent_id AS parent_id45, c0_.user_id AS user_id46 
FROM comment c0_ 
LEFT JOIN comment_thread c1_ ON c0_.thread_id = c1_.id 
LEFT JOIN customer_user c2_ ON c0_.user_id = c2_.id 
WHERE c1_.site_id = 2 AND c0_.state = 1 
ORDER BY c0_.created_at DESC LIMIT 10;

如果你有一个解决方案......我会很棒!

非常感谢 !

- - - - - - - - - 更新 : - - - - - - - - -

在你回答之后,我重新运行测试,我仍然有“使用文件排序”。

如果你有一个想法,告诉我让它消失。我无法删除 ORDER BY 语句。

mysql> EXPLAIN
    -> SELECT c0_.id AS id0, c0_.body AS body1, c0_.created_at AS created_at2, c0_.state AS state3, c0_.abuse_count AS abuse_count4, c0_.prediction_1 AS prediction_15, c0_.prediction_2 AS prediction_26, c0_.prediction_3 AS prediction_37, c0_.prediction_4 AS prediction_48, c0_.prediction_5 AS prediction_59, c0_.prediction_6 AS prediction_610, c0_.prediction_7 AS prediction_711, c0_.prediction_8 AS prediction_812, c0_.prono_concours AS prono_concours13, c0_.prono_points AS prono_points14, c1_.id AS id15, c1_.is_commentable AS is_commentable16, c1_.num_comments AS num_comments17, c1_.last_comment_at AS last_comment_at18, c1_.site_id AS site_id19, c1_.content_id AS content_id20, c1_.content_type AS content_type21, c1_.race_date AS race_date22, c1_.num_race AS num_race23, c2_.username AS username24, c2_.username_canonical AS username_canonical25, c2_.email AS email26, c2_.email_canonical AS email_canonical27, c2_.enabled AS enabled28, c2_.salt AS salt29, c2_.password AS password30, c2_.last_login AS last_login31, c2_.locked AS locked32, c2_.expired AS expired33, c2_.expires_at AS expires_at34, c2_.confirmation_token AS confirmation_token35, c2_.password_requested_at AS password_requested_at36, c2_.roles AS roles37, c2_.credentials_expired AS credentials_expired38, c2_.credentials_expire_at AS credentials_expire_at39, c2_.id AS id40, c2_.date_subscription AS date_subscription41, c2_.last_login_ip AS last_login_ip42, c2_.ref_client_le_turf AS ref_client_le_turf43, c0_.thread_id AS thread_id44, c0_.parent_id AS parent_id45, c0_.user_id AS user_id46
    -> FROM comment c0_
    -> INNER JOIN comment_thread c1_ ON c0_.thread_id = c1_.id
    -> INNER JOIN customer_user c2_ ON c0_.user_id = c2_.id
    -> WHERE c1_.site_id = 2 AND c0_.state = 1
    -> ORDER BY c0_.created_at DESC LIMIT 10;
+----+-------------+-------+--------+---------------------------------------------------------------------------+----------------------+---------+--------------------------+------+----------------------------------------------+
| id | select_type | table | type   | possible_keys                                                             | key                  | key_len | ref                      | rows | Extra                                        |
+----+-------------+-------+--------+---------------------------------------------------------------------------+----------------------+---------+--------------------------+------+----------------------------------------------+
|  1 | SIMPLE      | c1_   | range  | PRIMARY,UNIQ_COMMENT_SITEID,IDX_SITEID,IDX_ID_SITEID                      | UNIQ_COMMENT_SITEID  | 4       | NULL                     |  234 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | c0_   | ref    | IDX_9474526CE2904019,IDX_9474526CA76ED395,IDX_STATE,IDX_STATE_DATE_CREATE | IDX_9474526CE2904019 | 4       | turfeditions.c1_.id      |   16 | Using where                                  |
|  1 | SIMPLE      | c2_   | eq_ref | PRIMARY                                                                   | PRIMARY              | 4       | turfeditions.c0_.user_id |    1 |                                              |
+----+-------------+-------+--------+---------------------------------------------------------------------------+----------------------+---------+--------------------------+------+----------------------------------------------+
3 rows in set (0.00 sec)
4

1 回答 1

0

First, you will need to clarify something. Your LEFT-JOIN to the comment_thread table is processed as an INNER-JOIN since you have the "and c1_.site_id = 2". If you truly want it as a left-join, move the AND clause for site_id to the LEFT-JOIN... such as

   FROM 
      comment c0_ 
         LEFT JOIN comment_thread c1_ 
            ON c0_.thread_id = c1_.id 
           AND c1_.site_id = 2 
         LEFT JOIN customer_user c2_ 
            ON c0_.user_id = c2_.id 
   WHERE 
      c0_.state = 1
   ORDER BY 
      c0_.created_at DESC 
   LIMIT 10;

Now, that said, I would have an index on the comment_thread table on ( ID, Site_ID ). On the Comment table, I would have an index on (state, created_at).

Via the left-joins, it will pull all comments for state = 1 REGARDLESS of having a matching entry in the comment_thread or customer_user (even though every post would expect to have a user who posted it and left-join should really be just an INNER JOIN)

于 2013-07-10T01:55:37.773 回答