使用force index避免全索引扫描

mysql优化器经常使用错索引,这个时候就需要我们dba进行索引纠正。

看下面的sql

SELECT DISTINCT(p.products_id) FROM products AS p
INNER JOIN products_description AS pd USING(products_id)
LEFT JOIN products_to_categories AS pc ON pc.products_id=p.products_id
WHERE language_id=1 AND products_status = 1  AND p.products_date_added >= '2014-02-17'
 AND pc.categories_id NOT IN (1098,1212,1824,1826,1828,1825,1850,1827,1849,1851,1852,2086,1218,1842,1843,1844,1845,1846,1847,1838,1994,1210,1217,1987,1854,1219,1822,1820,1841,1213,1817,1819,1818,1821,1823,2150,1211,1647,2009,2010,2045) 
 ORDER BY  p.products_date_added DESC   LIMIT 0, 40;

获取20天新增的产品,并排除某些类别id进行展示。

在p.products_date_added 上有索引,我们理想的sql状态是利用p.products_date_added 索引;但是,因为categories_id也是索引,而且categories_id为整形,p.products_date_added 为时间类型,mysql优化器选择了categories_id,造成了products_to_categories全索引扫描.

explain

+----+-------------+-------+--------+-----------------------------+---------+---------+------------------------------------+--------+-----------------------------------------------------------+
| id | select_type | table | type   | possible_keys               | key     | key_len | ref                                | rows   | Extra                                                     |
+----+-------------+-------+--------+-----------------------------+---------+---------+------------------------------------+--------+-----------------------------------------------------------+
|  1 | SIMPLE      | pc    | index  | PRIMARY,categories_id       | PRIMARY | 8       | NULL                               | 102015 | Using where; Using index; Using temporary; Using filesort |
|  1 | SIMPLE      | pd    | eq_ref | PRIMARY                     | PRIMARY | 8       | banggood_work.pc.products_id,const |      1 | Using index                                               |
|  1 | SIMPLE      | p     | eq_ref | PRIMARY,products_date_added | PRIMARY | 4       | banggood_work.pc.products_id       |      1 | Using where                                               |
+----+-------------+-------+--------+-----------------------------+---------+---------+------------------------------------+--------+-----------------------------------------------------------+

profiling发现

| Status                         | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
+--------------------------------+----------+----------+------------+--------------+---------------+
| starting                       | 0.000027 | 0.000000 |   0.000000 |            0 |             0 |
| Waiting for query cache lock   | 0.000008 | 0.000000 |   0.000000 |            0 |             0 |
| checking query cache for query | 0.000132 | 0.000000 |   0.000000 |            0 |             0 |
| checking permissions           | 0.000008 | 0.000000 |   0.000000 |            0 |             0 |
| checking permissions           | 0.000007 | 0.000000 |   0.000000 |            0 |             0 |
| checking permissions           | 0.000009 | 0.000000 |   0.000000 |            0 |             0 |
| Opening tables                 | 0.000037 | 0.000000 |   0.000000 |            0 |             0 |
| System lock                    | 0.000016 | 0.000000 |   0.000000 |            0 |             0 |
| Waiting for query cache lock   | 0.000116 | 0.000000 |   0.000000 |            0 |             0 |
| init                           | 0.000272 | 0.000000 |   0.000000 |            0 |             0 |
| optimizing                     | 0.000033 | 0.000000 |   0.000000 |            0 |             0 |
| statistics                     | 0.000517 | 0.000999 |   0.000000 |            0 |             0 |
| preparing                      | 0.000449 | 0.001000 |   0.000000 |            0 |             0 |
| Creating tmp table             | 0.000042 | 0.000000 |   0.000000 |            0 |             0 |
| executing                      | 0.000008 | 0.000000 |   0.000000 |            0 |             0 |
| Copying to tmp table           | 0.749170 | 0.464930 |   0.283956 |          272 |           440 |
| Sorting result                 | 0.000291 | 0.000000 |   0.000000 |            0 |             0 |
| Sending data                   | 0.000019 | 0.000000 |   0.000000 |            0 |             0 |
| end                            | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |
| removing tmp table             | 0.000054 | 0.000000 |   0.000000 |            0 |             0 |
| end                            | 0.000005 | 0.000000 |   0.000000 |            0 |             0 |
| query end                      | 0.000003 | 0.000000 |   0.000000 |            0 |             0 |
| closing tables                 | 0.000008 | 0.000000 |   0.000000 |            0 |             0 |
| freeing items                  | 0.000018 | 0.000000 |   0.000000 |            0 |             0 |
| Waiting for query cache lock   | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |
| freeing items                  | 0.000319 | 0.000999 |   0.000000 |            0 |             0 |
| Waiting for query cache lock   | 0.000007 | 0.000000 |   0.000000 |            0 |             0 |
| freeing items                  | 0.000003 | 0.000000 |   0.000000 |            0 |             0 |
| storing result in query cache  | 0.000005 | 0.000000 |   0.000000 |            0 |             0 |
| logging slow query             | 0.000003 | 0.000000 |   0.000000 |            0 |             0 |
| logging slow query             | 0.000029 | 0.000000 |   0.000000 |            0 |             0 |
| cleaning up                    | 0.000008 | 0.000000 |   0.000000 |            0 |             0 |
+--------------------------------+----------+----------+------------+--------------+---------------+

执行时间为0.74s,其中Copying to tmp table一项占据了大量io和cpu。

我们可以使用force index强制告诉sql优化器使用哪个索引,更改后如下

EXPLAIN SELECT DISTINCT(p.products_id) FROM products AS p FORCE INDEX(products_date_added)
    -> INNER JOIN products_description AS pd USING(products_id)
    -> LEFT JOIN products_to_categories AS pc ON pc.products_id=p.products_id
    -> WHERE language_id=1 AND products_status = 1  AND p.products_date_added >= '2014-02-17'
    ->  AND pc.categories_id NOT IN (1098,1212,1824,1826,1828,1825,1850,1827,1849,1851,1852,2086,1218,1842,1843,1844,1845,1846,1847,1838,1994,1210,1217,1987,1854,1219,1822,1820,1841,1213,1817,1819,1818,1821,1823,2150,1211,1647,2009,2010,2045) 
    ->  ORDER BY  p.products_date_added DESC   LIMIT 0, 40;
+----+-------------+-------+--------+-----------------------+---------------------+---------+-----------------------------------+------+----------------------------------------------+
| id | select_type | table | type   | possible_keys         | key                 | key_len | ref                               | rows | Extra                                        |
+----+-------------+-------+--------+-----------------------+---------------------+---------+-----------------------------------+------+----------------------------------------------+
|  1 | SIMPLE      | p     | range  | products_date_added   | products_date_added | 8       | NULL                              | 1336 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | pd    | eq_ref | PRIMARY               | PRIMARY             | 8       | banggood_work.p.products_id,const |    1 | Using index; Distinct                        |
|  1 | SIMPLE      | pc    | ref    | PRIMARY,categories_id | PRIMARY             | 4       | banggood_work.p.products_id       | 1020 | Using where; Using index; Distinct           |
+----+-------------+-------+--------+-----------------------+---------------------+---------+-----------------------------------+------+----------------------------------------------+

发现已经使用我们预期中的索引products_date_added,

profiling的结果呢?

| Status                         | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
+--------------------------------+----------+----------+------------+--------------+---------------+
| starting                       | 0.000017 | 0.000000 |   0.000000 |            0 |             0 |
| Waiting for query cache lock   | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |
| checking query cache for query | 0.000080 | 0.000000 |   0.000000 |            0 |             0 |
| checking permissions           | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |
| checking permissions           | 0.000003 | 0.000000 |   0.000000 |            0 |             0 |
| checking permissions           | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |
| Opening tables                 | 0.000018 | 0.000000 |   0.000000 |            0 |             0 |
| System lock                    | 0.000008 | 0.000000 |   0.000000 |            0 |             0 |
| Waiting for query cache lock   | 0.000026 | 0.000000 |   0.000000 |            0 |             0 |
| init                           | 0.000130 | 0.000000 |   0.000000 |            0 |             0 |
| optimizing                     | 0.000019 | 0.000000 |   0.000000 |            0 |             0 |
| statistics                     | 0.000251 | 0.000000 |   0.000000 |            0 |             0 |
| preparing                      | 0.000035 | 0.000000 |   0.000000 |            0 |             0 |
| Creating tmp table             | 0.000022 | 0.000000 |   0.000000 |            0 |             0 |
| executing                      | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |
| Copying to tmp table           | 0.019651 | 0.009999 |   0.009999 |            0 |             0 |
| Sorting result                 | 0.000238 | 0.000000 |   0.000000 |            0 |             0 |
| Sending data                   | 0.000016 | 0.000000 |   0.000000 |            0 |             0 |
| end                            | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |
| removing tmp table             | 0.000006 | 0.000000 |   0.000000 |            0 |             0 |
| end                            | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |
| query end                      | 0.000003 | 0.000000 |   0.000000 |            0 |             0 |
| closing tables                 | 0.000007 | 0.000000 |   0.000000 |            0 |             0 |
| freeing items                  | 0.000011 | 0.000000 |   0.000000 |            0 |             0 |
| Waiting for query cache lock   | 0.000004 | 0.000000 |   0.000000 |            0 |             0 |
| freeing items                  | 0.000013 | 0.000000 |   0.001000 |            0 |             0 |
| Waiting for query cache lock   | 0.000003 | 0.000000 |   0.000000 |            0 |             0 |
| freeing items                  | 0.000003 | 0.000000 |   0.000000 |            0 |             0 |
| storing result in query cache  | 0.000005 | 0.000000 |   0.000000 |            0 |             0 |
| logging slow query             | 0.000003 | 0.000000 |   0.000000 |            0 |             0 |
| cleaning up                    | 0.000003 | 0.000000 |   0.000000 |            0 |             0 |
+--------------------------------+----------+----------+------------+--------------+---------------+

执行时间变为0.02s,其中最好io和cpu的Copying to tmp table已经减少了上百倍!

因为这条语句执行频率非常高,所以优化后,性能体现非常明显。


你可能感兴趣的:(index,Force,Force,index全索引扫描,全索引扫描)