热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

8种常见的SQL错误用法(建议收藏)

点击上方[全栈开发者社区]→右上角[]→[设为星标⭐]前言MySQL在2016年仍然保持强劲的数据库流行度增长趋势。越来越多的客户将自己的应用建立在MySQL数据库之上&#x

点击上方[全栈开发者社区]右上角[...][设为星标⭐]

前言

MySQL在2016年仍然保持强劲的数据库流行度增长趋势。越来越多的客户将自己的应用建立在MySQL数据库之上,甚至是从Oracle迁移到MySQL上来。但也存在部分客户在使用MySQL数据库的过程中遇到一些比如响应时间慢,CPU打满等情况。阿里云RDS专家服务团队帮助云上客户解决过很多紧急问题。现将《ApsaraDB专家诊断报告》中出现的部分常见SQL问题总结如下,供大家参考。

常见SQL错误用法

1. LIMIT 语句

分页查询是最常用的场景之一,但也通常也是最容易出问题的地方。比如对于下面简单的语句,一般DBA想到的办法是在type, name, create_time字段上加组合索引。这样条件排序都能有效的利用到索引,性能迅速提升。

SELECT * 
FROM   operation 
WHERE  type = 'SQLStats' AND name = 'SlowLog' 
ORDER  BY create_time 
LIMIT  1000, 10; 

好吧,可能90%以上的DBA解决该问题就到此为止。但当 LIMIT 子句变成 “LIMIT 1000000,10” 时,程序员仍然会抱怨:我只取10条记录为什么还是慢?

要知道数据库也并不知道第1000000条记录从什么地方开始,即使有索引也需要从头计算一次。出现这种性能问题,多数情形下是程序员偷懒了。在前端数据浏览翻页,或者大数据分批导出等场景下,是可以将上一页的最大值当成参数作为查询条件的。SQL重新设计如下:

SELECT   * 
FROM     operation 
WHERE    type = 'SQLStats' 
AND      name = 'SlowLog' 
AND      create_time > '2017-03-16 14:00:00' 
ORDER BY create_time limit 10;

在新设计下查询时间基本固定,不会随着数据量的增长而发生变化。

2. 隐式转换

SQL语句中查询变量和字段定义类型不匹配是另一个常见的错误。比如下面的语句:

mysql> explain extended SELECT * > FROM   my_balance b > WHERE  b.bpn = 14000000123 >       AND b.isverified IS NULL ;
mysql> show warnings;
| Warning | 1739 | Cannot use ref access on index 'bpn' due to type or collation conversion on field 'bpn'

其中字段bpn的定义为varchar(20),MySQL的策略是将字符串转换为数字之后再比较。函数作用于表字段,索引失效。

上述情况可能是应用程序框架自动填入的参数,而不是程序员的原意。现在应用框架很多很繁杂,使用方便的同时也小心它可能给自己挖坑。

3. 关联更新、删除

虽然MySQL5.6引入了物化特性,但需要特别注意它目前仅仅针对查询语句的优化。对于更新或删除需要手工重写成JOIN。

比如下面UPDATE语句,MySQL实际执行的是循环/嵌套子查询(DEPENDENT SUBQUERY),其执行时间可想而知。

UPDATE operation o 
SET    status = 'applying' 
WHERE  o.id IN (SELECT id FROM   (SELECT o.id, o.status FROM   operation o WHERE  o.group = 123 AND o.status NOT IN ( 'done' ) ORDER  BY o.parent, o.id LIMIT  1) t); 

执行计划:

+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+
| id | select_type        | table | type  | possible_keys | key     | key_len | ref   | rows | Extra                                               |
+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+
| 1  | PRIMARY            | o     | index |               | PRIMARY | 8       |       | 24   | Using where; Using temporary                        |
| 2  | DEPENDENT SUBQUERY |       |       |               |         |         |       |      | Impossible WHERE noticed after reading const tables |
| 3  | DERIVED            | o     | ref   | idx_2,idx_5   | idx_5   | 8       | const | 1    | Using where; Using filesort                         |
+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+

重写为JOIN之后,子查询的选择模式从DEPENDENT SUBQUERY变成DERIVED,执行速度大大加快,从7秒降低到2毫秒。

UPDATE operation o JOIN  (SELECT o.id, o.status FROM   operation o WHERE  o.group = 123 AND o.status NOT IN ( 'done' ) ORDER  BY o.parent, o.id LIMIT  1) tON o.id = t.id 
SET    status = 'applying' 

执行计划简化为:

+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+
| id | select_type | table | type | possible_keys | key   | key_len | ref   | rows | Extra                                               |
+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+
| 1  | PRIMARY     |       |      |               |       |         |       |      | Impossible WHERE noticed after reading const tables |
| 2  | DERIVED     | o     | ref  | idx_2,idx_5   | idx_5 | 8       | const | 1    | Using where; Using filesort                         |
+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+

4. 混合排序

MySQL不能利用索引进行混合排序。但在某些场景,还是有机会使用特殊方法提升性能的。

SELECT * 
FROM   my_order o INNER JOIN my_appraise a ON a.orderid = o.id 
ORDER  BY a.is_reply ASC, a.appraise_time DESC 
LIMIT  0, 20 

执行计划显示为全表扫描:

+----+-------------+-------+--------+-------------+---------+---------+---------------+---------+-+
| id | select_type | table | type   | possible_keys     | key     | key_len | ref      | rows    | Extra    
+----+-------------+-------+--------+-------------+---------+---------+---------------+---------+-+
|  1 | SIMPLE      | a     | ALL    | idx_orderid | NULL    | NULL    | NULL    | 1967647 | Using filesort |
|  1 | SIMPLE      | o     | eq_ref | PRIMARY     | PRIMARY | 122     | a.orderid |       1 | NULL           |
+----+-------------+-------+--------+---------+---------+---------+-----------------+---------+-+

由于is_reply只有0和1两种状态,我们按照下面的方法重写后,执行时间从1.58秒降低到2毫秒。

SELECT * 
FROM   ((SELECT *FROM   my_order o INNER JOIN my_appraise a ON a.orderid = o.id AND is_reply = 0 ORDER  BY appraise_time DESC LIMIT  0, 20) UNION ALL (SELECT *FROM   my_order o INNER JOIN my_appraise a ON a.orderid = o.id AND is_reply = 1 ORDER  BY appraise_time DESC LIMIT  0, 20)) t 
ORDER  BY  is_reply ASC, appraisetime DESC 
LIMIT  20; 

5. EXISTS语句

MySQL对待EXISTS子句时,仍然采用嵌套子查询的执行方式。如下面的SQL语句:

SELECT *
FROM   my_neighbor n LEFT JOIN my_neighbor_apply sra ON n.id = sra.neighbor_id AND sra.user_id = 'xxx' 
WHERE  n.topic_status < 4 AND EXISTS(SELECT 1 FROM   message_info m WHERE  n.id &#61; m.neighbor_id AND m.inuser &#61; &#39;xxx&#39;) AND n.topic_type <> 5 

执行计划为&#xff1a;

&#43;----&#43;--------------------&#43;-------&#43;------&#43;-----&#43;------------------------------------------&#43;---------&#43;-------&#43;---------&#43; -----&#43;
| id | select_type        | table | type | possible_keys     | key   | key_len | ref   | rows    | Extra   |
&#43;----&#43;--------------------&#43;-------&#43;------&#43; -----&#43;------------------------------------------&#43;---------&#43;-------&#43;---------&#43; -----&#43;
|  1 | PRIMARY            | n     | ALL  |  | NULL     | NULL    | NULL  | 1086041 | Using where                   |
|  1 | PRIMARY            | sra   | ref  |  | idx_user_id | 123     | const |       1 | Using where          |
|  2 | DEPENDENT SUBQUERY | m     | ref  |  | idx_message_info   | 122     | const |       1 | Using index condition; Using where |
&#43;----&#43;--------------------&#43;-------&#43;------&#43; -----&#43;------------------------------------------&#43;---------&#43;-------&#43;---------&#43; -----&#43;

去掉exists更改为join&#xff0c;能够避免嵌套子查询&#xff0c;将执行时间从1.93秒降低为1毫秒。

SELECT *
FROM   my_neighbor n INNER JOIN message_info m ON n.id &#61; m.neighbor_id AND m.inuser &#61; &#39;xxx&#39; LEFT JOIN my_neighbor_apply sra ON n.id &#61; sra.neighbor_id AND sra.user_id &#61; &#39;xxx&#39; 
WHERE  n.topic_status < 4 AND n.topic_type <> 5 

新的执行计划&#xff1a;

&#43;----&#43;-------------&#43;-------&#43;--------&#43; -----&#43;------------------------------------------&#43;---------&#43; -----&#43;------&#43; -----&#43;
| id | select_type | table | type   | possible_keys     | key       | key_len | ref   | rows | Extra                 |
&#43;----&#43;-------------&#43;-------&#43;--------&#43; -----&#43;------------------------------------------&#43;---------&#43; -----&#43;------&#43; -----&#43;
|  1 | SIMPLE      | m     | ref    | | idx_message_info   | 122     | const    |    1 | Using index condition |
|  1 | SIMPLE      | n     | eq_ref | | PRIMARY   | 122     | ighbor_id |    1 | Using where      |
|  1 | SIMPLE      | sra   | ref    | | idx_user_id | 123     | const     |    1 | Using where           |
&#43;----&#43;-------------&#43;-------&#43;--------&#43; -----&#43;------------------------------------------&#43;---------&#43; -----&#43;------&#43; -----&#43;

6. 条件下推

外部查询条件不能够下推到复杂的视图或子查询的情况有&#xff1a;

  1. 聚合子查询&#xff1b;

  2. 含有LIMIT的子查询&#xff1b;

  3. UNION 或UNION ALL子查询&#xff1b;

  4. 输出字段中的子查询&#xff1b;

如下面的语句&#xff0c;从执行计划可以看出其条件作用于聚合子查询之后&#xff1a;

SELECT * 
FROM   (SELECT target, Count(*) FROM   operation GROUP  BY target) t 
WHERE  target &#61; &#39;rm-xxxx&#39; 
&#43;----&#43;-------------&#43;------------&#43;-------&#43;---------------&#43;-------------&#43;---------&#43;-------&#43;------&#43;-------------&#43;
| id | select_type | table      | type  | possible_keys | key         | key_len | ref   | rows | Extra       |
&#43;----&#43;-------------&#43;------------&#43;-------&#43;---------------&#43;-------------&#43;---------&#43;-------&#43;------&#43;-------------&#43;
|  1 | PRIMARY     |  | ref   |    |  | 514     | const |    2 | Using where |
|  2 | DERIVED     | operation  | index | idx_4         | idx_4       | 519     | NULL  |   20 | Using index |
&#43;----&#43;-------------&#43;------------&#43;-------&#43;---------------&#43;-------------&#43;---------&#43;-------&#43;------&#43;-------------&#43;

确定从语义上查询条件可以直接下推后&#xff0c;重写如下&#xff1a;

SELECT target, Count(*) 
FROM   operation 
WHERE  target &#61; &#39;rm-xxxx&#39; 
GROUP  BY target

执行计划变为&#xff1a;

&#43;----&#43;-------------&#43;-----------&#43;------&#43;---------------&#43;-------&#43;---------&#43;-------&#43;------&#43;--------------------&#43;
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
&#43;----&#43;-------------&#43;-----------&#43;------&#43;---------------&#43;-------&#43;---------&#43;-------&#43;------&#43;--------------------&#43;
| 1 | SIMPLE | operation | ref | idx_4 | idx_4 | 514 | const | 1 | Using where; Using index |
&#43;----&#43;-------------&#43;-----------&#43;------&#43;---------------&#43;-------&#43;---------&#43;-------&#43;------&#43;--------------------&#43;

关于MySQL外部条件不能下推的详细解释说明请参考以前文章&#xff1a;MySQL · 性能优化 · 条件下推到物化表

7. 提前缩小范围

先上初始SQL语句&#xff1a;

SELECT * 
FROM   my_order o LEFT JOIN my_userinfo u ON o.uid &#61; u.uidLEFT JOIN my_productinfo p ON o.pid &#61; p.pid 
WHERE  ( o.display &#61; 0 ) AND ( o.ostaus &#61; 1 ) 
ORDER  BY o.selltime DESC 
LIMIT  0, 15 

该SQL语句原意是&#xff1a;先做一系列的左连接&#xff0c;然后排序取前15条记录。从执行计划也可以看出&#xff0c;最后一步估算排序记录数为90万&#xff0c;时间消耗为12秒。

&#43;----&#43;-------------&#43;-------&#43;--------&#43;---------------&#43;---------&#43;---------&#43;-----------------&#43;--------&#43;----------------------------------------------------&#43;
| id | select_type | table | type   | possible_keys | key     | key_len | ref             | rows   | Extra                                              |
&#43;----&#43;-------------&#43;-------&#43;--------&#43;---------------&#43;---------&#43;---------&#43;-----------------&#43;--------&#43;----------------------------------------------------&#43;
|  1 | SIMPLE      | o     | ALL    | NULL          | NULL    | NULL    | NULL            | 909119 | Using where; Using temporary; Using filesort       |
|  1 | SIMPLE      | u     | eq_ref | PRIMARY       | PRIMARY | 4       | o.uid |      1 | NULL                                               |
|  1 | SIMPLE      | p     | ALL    | PRIMARY       | NULL    | NULL    | NULL            |      6 | Using where; Using join buffer (Block Nested Loop) |
&#43;----&#43;-------------&#43;-------&#43;--------&#43;---------------&#43;---------&#43;---------&#43;-----------------&#43;--------&#43;----------------------------------------------------&#43;

由于最后WHERE条件以及排序均针对最左主表&#xff0c;因此可以先对my_order排序提前缩小数据量再做左连接。SQL重写后如下&#xff0c;执行时间缩小为1毫秒左右。

SELECT * 
FROM (
SELECT * 
FROM   my_order o 
WHERE  ( o.display &#61; 0 ) AND ( o.ostaus &#61; 1 ) 
ORDER  BY o.selltime DESC 
LIMIT  0, 15
) o LEFT JOIN my_userinfo u ON o.uid &#61; u.uid LEFT JOIN my_productinfo p ON o.pid &#61; p.pid 
ORDER BY  o.selltime DESC
limit 0, 15

再检查执行计划&#xff1a;子查询物化后&#xff08;select_type&#61;DERIVED)参与JOIN。虽然估算行扫描仍然为90万&#xff0c;但是利用了索引以及LIMIT 子句后&#xff0c;实际执行时间变得很小。

&#43;----&#43;-------------&#43;------------&#43;--------&#43;---------------&#43;---------&#43;---------&#43;-------&#43;--------&#43;----------------------------------------------------&#43;
| id | select_type | table      | type   | possible_keys | key     | key_len | ref   | rows   | Extra                                              |
&#43;----&#43;-------------&#43;------------&#43;--------&#43;---------------&#43;---------&#43;---------&#43;-------&#43;--------&#43;----------------------------------------------------&#43;
|  1 | PRIMARY     |  | ALL    | NULL          | NULL    | NULL    | NULL  |     15 | Using temporary; Using filesort                    |
|  1 | PRIMARY     | u          | eq_ref | PRIMARY       | PRIMARY | 4       | o.uid |      1 | NULL                                               |
|  1 | PRIMARY     | p          | ALL    | PRIMARY       | NULL    | NULL    | NULL  |      6 | Using where; Using join buffer (Block Nested Loop) |
|  2 | DERIVED     | o          | index  | NULL          | idx_1   | 5       | NULL  | 909112 | Using where                                        |
&#43;----&#43;-------------&#43;------------&#43;--------&#43;---------------&#43;---------&#43;---------&#43;-------&#43;--------&#43;----------------------------------------------------&#43;

8. 中间结果集下推

再来看下面这个已经初步优化过的例子(左连接中的主表优先作用查询条件)&#xff1a;

SELECT    a.*, c.allocated 
FROM      ( SELECT   resourceid FROM     my_distribute d WHERE    isdelete &#61; 0 AND      cusmanagercode &#61; &#39;1234567&#39; ORDER BY salecode limit 20) a 
LEFT JOIN ( SELECT   resourcesid&#xff0c; sum(ifnull(allocation, 0) * 12345) allocated FROM     my_resources GROUP BY resourcesid) c 
ON        a.resourceid &#61; c.resourcesid

那么该语句还存在其它问题吗&#xff1f;不难看出子查询 c 是全表聚合查询&#xff0c;在表数量特别大的情况下会导致整个语句的性能下降。

其实对于子查询 c&#xff0c;左连接最后结果集只关心能和主表resourceid能匹配的数据。因此我们可以重写语句如下&#xff0c;执行时间从原来的2秒下降到2毫秒。

SELECT    a.*, c.allocated 
FROM      ( SELECT   resourceid FROM     my_distribute d WHERE    isdelete &#61; 0 AND      cusmanagercode &#61; &#39;1234567&#39; ORDER BY salecode limit 20) a 
LEFT JOIN ( SELECT   resourcesid&#xff0c; sum(ifnull(allocation, 0) * 12345) allocated FROM     my_resources r, ( SELECT   resourceid FROM     my_distribute d WHERE    isdelete &#61; 0 AND      cusmanagercode &#61; &#39;1234567&#39; ORDER BY salecode limit 20) a WHERE    r.resourcesid &#61; a.resourcesid GROUP BY resourcesid) c 
ON        a.resourceid &#61; c.resourcesid

但是子查询 a 在我们的SQL语句中出现了多次。这种写法不仅存在额外的开销&#xff0c;还使得整个语句显的繁杂。使用WITH语句再次重写&#xff1a;

WITH a AS 
( SELECT   resourceid FROM     my_distribute d WHERE    isdelete &#61; 0 AND      cusmanagercode &#61; &#39;1234567&#39; ORDER BY salecode limit 20)
SELECT    a.*, c.allocated 
FROM      a 
LEFT JOIN ( SELECT   resourcesid&#xff0c; sum(ifnull(allocation, 0) * 12345) allocated FROM     my_resources r, a WHERE    r.resourcesid &#61; a.resourcesid GROUP BY resourcesid) c 
ON        a.resourceid &#61; c.resourcesid

AliSQL即将推出WITH语法&#xff0c;敬请期待。

总结

  1. 数据库编译器产生执行计划&#xff0c;决定着SQL的实际执行方式。但是编译器只是尽力服务&#xff0c;所有数据库的编译器都不是尽善尽美的。上述提到的多数场景&#xff0c;在其它数据库中也存在性能问题。了解数据库编译器的特性&#xff0c;才能避规其短处&#xff0c;写出高性能的SQL语句。

  2. 程序员在设计数据模型以及编写SQL语句时&#xff0c;要把算法的思想或意识带进来。

  3. 编写复杂SQL语句要养成使用WITH语句的习惯。简洁且思路清晰的SQL语句也能减小数据库的负担 ^^。

  4. 使用云上数据库遇到难点&#xff08;不局限于SQL问题&#xff09;&#xff0c;随时寻求阿里云原厂专家服务的帮助。

作者 | db匠

来源 | http://yq.aliyun.com/articles/72501

觉得本文对你有帮助&#xff1f;请分享给更多人关注「全栈开发者社区」加星标&#xff0c;提升全栈技能
本公众号会不定期给大家发福利&#xff0c;包括送书、学习资源等&#xff0c;敬请期待吧&#xff01;
如果感觉推送内容不错&#xff0c;不妨右下角点个在看转发朋友圈或收藏&#xff0c;感谢支持。
好文章&#xff0c;留言、点赞、在看和分享一条龙吧❤️


推荐阅读
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • ubuntu用sqoop将数据从hive导入mysql时,命令: ... [详细]
author-avatar
一条游荡在重庆的鱼_759
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有