此表及其查询的最佳优化是什么?

时间:2015-09-29 22:43:25

标签: mysql indexing query-optimization

我有这张桌子:

CREATE TABLE IF NOT EXISTS `listings` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `type` tinyint(1) NOT NULL DEFAULT '1',
  `hash` char(32) NOT NULL,
  `source_id` int(10) unsigned NOT NULL,
  `link` varchar(255) NOT NULL,
  `short_link` varchar(255) NOT NULL,
  `cat_id` mediumint(5) NOT NULL,
  `title` mediumtext NOT NULL,
  `description` mediumtext,
  `content` mediumtext,
  `images` mediumtext,
  `videos` mediumtext,
  `views` int(10) NOT NULL,
  `comments` int(11) NOT NULL DEFAULT '0',
  `comments_update` int(11) NOT NULL DEFAULT '0',
  `editor_id` int(11) NOT NULL DEFAULT '0',
  `auther_name` varchar(255) DEFAULT NULL,
  `createdby_id` int(10) NOT NULL,
  `createdon` int(20) NOT NULL,
  `editedby_id` int(10) NOT NULL,
  `editedon` int(20) NOT NULL,
  `deleted` tinyint(1) NOT NULL,
  `deletedon` int(20) NOT NULL,
  `deletedby_id` int(10) NOT NULL,
  `deletedfor` varchar(255) NOT NULL,
  `published` tinyint(1) NOT NULL DEFAULT '1',
  `publishedon` int(20) NOT NULL,
  `publishedby_id` int(10) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `hash` (`hash`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT AUTO_INCREMENT=91628 ;

和一些像这样的错误查询

SELECT  id,type , source_id, link, short_link, cat_id, title,
        description, images, views, comments, published, publishedon,
        content, comments_update, editor_id, auther_name, createdby_id,
        createdon, editedby_id, editedon, deleted, deletedon,
        deletedby_id, deletedfor, publishedby_id
    FROM  listings
    WHERE  (cat_id IN ( 98 ))
      AND  (TYPE IN ('1'))
      AND  (source_id IN ('78'))AND (FROM_UNIXTIME( publishedon ) >= SUBDATE( NOW( ) ,
                        1 )
           )
      AND  (deleted =0)
      AND  (published =1)
    ORDER BY  `publishedon` DESC
    LIMIT  10 OFFSET 0 

SELECT  id,type,source_id,link,short_link,cat_id,title,description,
       images,views,comments,published,publishedon
    FROM  listings
    WHERE  (title RLIKE 'اليمن|عدن')
      AND  (id != 89024)
      AND  (deleted = 0)
      AND  (published = 1)
    ORDER BY  publishedon DESC
    LIMIT  6 OFFSET 0 

SELECT MIN(id) FROM listings
    WHERE (id > 91152) AND (cat_id = '134')

SELECT  COUNT(id)
    FROM  listings
    WHERE  (publishedon >= '1442963362'
              AND  publishedon <= '1443568162'
           )
      AND  (cat_id IN ('19', '20', '21', '22', '23', '24', '27',
                        '32', '35', '110', '54', '38', '39', '41', '42', '43',
                        '44', '45', '46', '47', '49', '56', '57', '51', '55',
                        '58', '59', '60', '61', '62', '102', '95', '96', '98',
                        '101', '103', '104', '105', '106', '124', '125', '130',
                        '131', '132', '133', '134', '135')
           ) 

此查询可能需要0.4秒才能完成。任何在一个页面中,它可能包含5个这样的查询。这是一个非常大的问题;它会导致服务器负载和停机时间。

此查询

SELECT *
FROM `listings`
WHERE id = 5455

需要0.0004秒才能完成,因为它取决于pk的索引

如何在第一个查询中为列创建索引?

很多时候,当我使用&#34; show processlist&#34;时,我看到了这个&#34;等待表级锁定&#34;太多了&#34;排序数据&#34;。

应用程序一直插入/更新许多行;我怎么解决这个问题?

2 个答案:

答案 0 :(得分:2)

您的查询基本上是:

SELECT . . .
FROM listings l
WHERE cat_id = 98 AND
      TYPE = 1 AND
      source_id = 78 AND
      deleted = 0 AND
      published = 1 AND
      FROM_UNIXTIME( publishedon ) >= SUBDATE( NOW( ) , 1 )
ORDER BY `publishedon` DESC
LIMIT 10
OFFSET 0 

对于性能,从(cat_id, type, source_id, deleted, published, publishedon)上的复合索引开始。语法是:

create index idx_listings_6 on listings(cat_id, type, source_id, deleted, published, publishedon desc);

接下来,我建议将where子句重写为:

SELECT . . .
FROM listings l
WHERE cat_id = 98 AND
      TYPE = 1 AND
      source_id = 78 AND
      deleted = 0 AND
      published = 1 AND
      publishedon >= UNIX_TIMESTAMP(SUBDATE( NOW( ) , 1 ))
ORDER BY `publishedon` DESC
LIMIT 10
OFFSET 0 

并使用上面相同的索引。

答案 1 :(得分:0)

MySQL无法将索引声明为DESC;它会忽略该关键字并构建ASC索引。但是,ORDER BY x DESC仍然可以优化。

MySQL每个SELECT只使用一个INDEX。 (一般)。

最佳索引以&#39; =&#39;的任何WHERE子句字段开头。

查询1:已经讨论过。

查询2:INDEX(deleted, published, publishedon)

查询3:INDEX(cat_id, id)

问题4:将COUNT(id)更改为COUNT(*)并添加INDEX(cat_id, publishedon)和/或INDEX(publishedon, cat_id)。不明显哪个指数会更好。添加两者并让优化器决定。与您的其他问题一样,PARTITION BY RANGE(publishedon)使用INDEX(cat_id, publishedon)(而非另一个)可能会有所帮助。

考虑切换到InnoDB。