/** * 超时 * * @param time * @return */ public int numPairsDivisibleBy60(int[] time) { int result = 0; for (int i = 0; i < time.length - 1; i++) { for (int j = i + 1; j < time.length; j++) { int value = (time[i] + time[j]) % 60; if (value == 0) result++; } } return result; }
public int numPairsDivisibleBy601(int[] time) { // 每个元素取60余 time = Arrays.stream(time).map(x -> x % 60).toArray(); int[] arrCount = new int[60]; // 统计对应下标数 Arrays.stream(time).forEach(x -> { arrCount[x]++; }); // 余数是 0 或 30 的两两配对 int result = qiuhe(arrCount[0]) + qiuhe(arrCount[30]); // 其余互相配对 for (int i = 1; i < 30; i++) { int count1 = arrCount[i]; int count2 = arrCount[60 - i]; result += count1 * count2; } return result; }
/** * 求两两配对数 * * @param num * @return */ private int qiuhe(int num) { if (num < 2) return 0; // (num-1)! return num * (num - 1) / 2; }
很好理解,不过速度还是慢,通过阅读其它人的代码后发现了另一种 O(n) 解法,cool~
1 2 3 4 5 6 7 8 9 10 11 12 13
public int numPairsDivisibleBy602(int[] time) { int result = 0; int[] arrCount = new int[60]; for (int t : time) { // 对应的下标 int index = t == 0 ? 0 : 60 - t % 60; // 与已经统计的数进行匹配 可防止两两重复匹配 result += arrCount[index]; // 对应数字加一 arrCount[t % 60]++; } return result; }
public ListNode reverseBetween(ListNode head, int m, int n) { if (head == null) return null; // 新建一个节点并指向 head ListNode dummy = new ListNode(0); dummy.next = head; ListNode pre = dummy; // pre 为需要反转的前节点 for (int i = 0; i < m - 1; i++) pre = pre.next;
mysql> explain select id, sum(moneys) from sales2 group by id\G; **************************** 1. row ************************************* id: 1 select_type: SIMPLE table: sales2 type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1000 Extra: Using temporary; Using filesort 1 row in set(0.00 sec)
mysql> explain select id, sum(moneys) from sales2 group by id order by null\G; **************************** 1. row ************************************* id: 1 select_type: SIMPLE table: sales2 type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1000 Extra: Using temporary
从上面的例子可以看出第一个 SQL 语句需要进行“filesort”,而第二个 SQL 由于 ORDER BY NULL 不需要进行“filesort”,而 filesort 往往非常耗费时间。
优化 ORDER BY 语句
在某些情况中,MySQL 可以使用一个索引来满足 ORDER BY 子句,而不需要额外的排序。WHERE 条件和 ORDER BY 使用相同的索引,并且 ORDER BY 的顺序和索引顺序相同,并且 ORDER BY 的字段都是升序或者都是降序。
例如,下列 SQL 可以使用索引:
1 2 3
SELECT * FROM t1 ORDER BY key_part1,key_part2,...; SELECT * FROM t1 WHERE key_part1=1 ORDER BY key_part1 DESC, key_part2 DESC; SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 DESC;
但是在以下几种情况下则不使用索引:
1 2 3
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC; --order by 的字段混合 ASC 和 DESC SELECT * FROM t1 WHERE key2=constant ORDER BY key1; --用于查询行的关键字与 ORDER BY 中所使用的不相同 SELECT * FROM t1 ORDER BY key1, key2; --对不同的关键字使用 ORDER BY
优化嵌套查询
MySQL 4.1 开始支持 SQL 的子查询。这个技术可以使用 SELECT 语句来创建一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中。使用子查询可以一次性地完成很多逻辑上需要多个步骤才能完成的 SQL 操作,同时也可以避免事务或者表锁死,并且写起来也很容易。但是,有些情况下,子查询可以被更有效率的连接(JOIN)替代。
mysql> explain select * from company2 where name like '%3'\G; **************************** 1. row ************************************* id: 1 select_type: SIMPLE table: company2 type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1000 Extra: Using where 1 row in set(0.00 sec)
mysql> explain select * from company2 where name like '3%'\G; **************************** 1. row ************************************* id: 1 select_type: SIMPLE table: company2 type: range possible_keys: ind_company2_name key: ind_company2_name key_len: 11 ref: NULL rows: 103 Extra: Using where 1 row in set(0.00 sec)
(4)如果列名是索引,使用 column_name is null 将使用索引。如下例中查询 name 为 null 的记录就用到了索引:
1 2 3 4 5 6 7 8 9 10 11 12 13
mysql> explain select * from company2 where name is null\G; **************************** 1. row ************************************* id: 1 select_type: SIMPLE table: company2 type: ref possible_keys: ind_company2_name key: ind_company2_name key_len: 11 ref: const rows: 1 Extra: Using where 1 row in set(0.00 sec)
存在索引但不使用索引
在下列情况下,虽然存在索引,但是 MySQL 并不会使用相应的索引。
(1)如果 MySQL 估计使用索引比全表扫描更慢,则不使用索引。例如如果列 key_part1 均匀分布在 1 和 100 之间,下列查询中使用索引就不是很好:
1
SELECT * FROM table_name where key_part1 > 1 and key_part1 < 90;
(2)如果使用 MEMORY/HEAP 表并且 where 条件中不使用“=”进行索引列,那么不会用到索引。heap 表只有在“=”的条件下才会使用索引。
(3)用 or 分割开的条件,如果 or 前的条件中的列有索引,而后面的列中没有索引,那么涉及到的索引都不会被用到,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
mysql> show index from sales\G; **************************** 1. row ************************************* Table: sales Non_unique: 1 Key_name: ind_sales_year Seq_in_index: 1 Column_name: year Collation: A Cardinality: NULL Sub_part: NULL Packed: NULL Null: Index_type: BTREE Comment: 1 row in set(0.00 sec)
从上面可以发现只有 year 列上面有索引,来看如下的执行计划:
1 2 3 4 5 6 7 8 9 10 11 12 13
mysql> explain select * from sales where year = 2001 or country = 'China'\G; **************************** 1. row ************************************* id: 1 select_type: SIMPLE table: sales type: ALL possible_keys: ind_sales_year key: NULL key_len: NULL ref: NULL rows: 12 Extra: Using where 1 row in set(0.00 sec)
可见虽然在 year 这个列上存在索引 ind_sales_year,但是这个 SQL 语句并没有用到这个索引,原因就是 or 中有一个条件中的列没有索引。
(4)如果不是索引列的第一部分,如下例子:
1 2 3 4 5 6 7 8 9 10 11 12 13
mysql> explain select * from sales2 where moneys = 1\G; **************************** 1. row ************************************* id: 1 select_type: SIMPLE table: sales2 type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1000 Extra: Using where 1 row in set(0.00 sec)
可见虽然在 money 上面建有复合索引,但是由于 money 不是索引的第一列,那么在查询中这个索引也不会被 MySQL 采用。
(5)如果 like 是以 % 开始,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13
mysql> explain select * from company2 where name like '%3'\G; **************************** 1. row ************************************* id: 1 select_type: SIMPLE table: company2 type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1000 Extra: Using where 1 row in set(0.00 sec)
可见虽然在 name 上建有索引,但是由于 where 条件中 like 的值的“%”在第一位了,那么 MySQL 也不会采用这个索引。
(6)如果列类型是字符串,那么一定记得在 where 条件中把字符常量值用引号引起来,否则的话即便这个列上有索引,MySQL 也不会用到的,因为,MySQL 默认把输入的常量值进行转换以后才进行检索。如下面的例子中 company2 表中的 name 字段是字符型的,但是 SQL 语句中的条件值 294 是一个数值型值,因此即便在 name 上有索引,MySQL 也不能正确地用上索引,而是继续进行全表扫描。
MySQL 客户端连接成功后,通过 show[session|global] status 命令可以提供服务器状态信息,也可以在操作系统上使用 mysqladmin extended-status 命令获得这些消息。show[session|global] status 可以根据需要加上参数“session”或者“global”来显示 session 级(当前连接)的统计结果和 global 级(自数据库上次启动至今)的统计结果。如果不写,默认使用参数是“session”。