回答

收藏

             &

技术问答 技术问答 226 人阅读 | 0 人回复 | 2023-09-14

这是我的查询:7 u% I2 o3 M4 j
SELECT a.*FROM    articles AS a,   article_categories AS cWHERE    a.id = c.article_id    AND c.category_id = 78    AND a.comment_cnt > 0    AND a.deleted = 0ORDER BY a.last_updatedLIMIT 100,20并EXPLAIN为此:
# g: [4 F/ v% w1 N*************************** 1. row ***************************           id: 1  select_type: SIMPLE        table: a         type: indexpossible_keys: PRIMARY          key: last_updated      key_len:        ref: NULL         rows:                                                                 Extra: Using where*************************** 2. row ***************************           id: 1  select_type: SIMPLE        table: c         type: eq_refpossible_keys: PRIMARY,fandom_id          key: PRIMARY      key_len: 8                                                                                                                                                                                                                                                                                                                                                                              ref: db.a.id,const         rows:                 Extra: Using index它last_updated在第一个表上使用的全索引扫描进行排序,但不使用y连接索引(type:index在解释中)。这对性能非常不利,并且会杀死整个数据库服务器,因为这是一个非常频繁的查询。  G) X1 V5 F( l0 S. }
我试着使用反转表顺序STRAIGHT_JOIN,但这给了filesort,using_temporary,甚至更糟。
  k) I* p( _/ j: z该怎么办?mysql用索引连接排序?  Y# F8 V7 h, C
===更新===
1 Y/ [( y4 w3 W/ t. j" M- e我真的很绝望。也许这里可以帮助某种形式的非标准化?8 \$ e6 |7 p- @
                                                               
% |4 z0 U2 l: `' p! s3 U9 O! O    解决方案:                                                                ! T5 m( k# z8 N
                                                                如果您有许多类别,则无法提高此查询的效率。单个索引不能一次覆盖两个表MySQL。; W* `6 q/ i$ x. l+ V' u3 @
你要做的非标准化:添加last_updated,has_comments并deleted为article_categories:
2 L0 u/ U( T, z; b4 e' i; t% V6 YCREATE TABLE `article_categories` (  `article_id` int(11) NOT NULL DEFAULT '0', `category_id` int(11) NOT NULL DEFAULT '0', `last_updated` timestamp NOT NULL, `has_comments` boolean NOT NULL, `deleted` boolean NOT NULL, PRIMARY KEY (`article_id`,`category_id`), KEY `category_id` (`category_id`), KEY `ix_articlecategories_category_comments_deleted_updated` (category_id,has_comments,deleted,last_updated)) ENGINE=InnoDB DEFAULT CHARSET=utf8并运行以下查询:  d1 P, U6 ~. Z, ?
SELECT  *FROM    (            SELECT  article_id        FROM    article_categories        WHERE   (category_id,has_comments,deleted) =     ORDER BY                last_updated DESC        LIMIT             qJOIN    articles aON      a.id = q.article_id当然article_categories,每当您更新相关列时,您也应该更新article。可在触发器中完成。
8 c1 o. ?# [& `' o5 \. N7 z: N  O请注意,这个列has_comments是布尔值:这将允许使用相等谓词在单个范围内扫描索引。5 k+ x/ y" o6 O0 g
还要注意,LIMIT进入子查询MySQL默认情况下不使用的后续搜索。请参阅我的博客关于如何提高性能的文章:
: m- }4 {' u! lMySQL ORDER BY / LIMIT性能:晚行搜索假如你用的是SQL
! x+ g8 Y1 ?1 G) y3 J8 vServer,从本质上看,可以在查询中建立索引视图article_categories它将使用带有附加字段的服务器自动维护的非标准化索引副本。2 T8 q2 ]/ t" x5 O8 K1 M* `1 a* i
不幸的是,MySQL它不支持此功能,您必须手动创建此表并编写其他代码,以保持与基本表同步。
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则