mysql使用小技巧
2016-06-22 23:15
525 查看
1:影响MySQL查询结果的条件
1:硬件,2:网络I/O,3查询时间
查询的时间相关:数据表结构的建立,索引的应用,SQL语句的使用
我们后端工程师能够把握的主要是表结构,索引和SQL语句方面,可以通过工程师的智慧来减小公司的成本,优化用户的体验
目前的计算机系统使用的都是分时系统,可能是一个进程给一个用户提供服务。计算机在不同的进程间快速的切换(针对的是单核的原理),如果一个进程占用了太长的时间,不近会影响进程的排序时间,也会因为保存上下文占用空间的资源。所以优化查询就变的很重要了
2更好的查询:时间和空间使用的更少(内存和磁盘消耗,响应时间)
扫描的行数和返回的行数的比例较小
3.索引的优点
索引能减少服务器扫描数据量
可以帮助服务器避免排序和临时表
可以将随机I/O变为顺序I/O
创建索引的一个基本的判断
count(distinct field) / count(*)
4. B-tree的使用场景
更适合有比较的范围的查询:>,<,between
因为只用叶子节点存储数据,其余的节点存储的是数据的范围值(
比保存在左子树的任何键值都要大比保存在右子树的任何键值都要小
)
使用索引的经验之谈:where条件中,group by中的,表连接中的on判断语句中的都可以根据实际的情况来创建索引
使用的是多列的索引还是单列的索引也要根据实际的情况来判定
5.SQL的执行顺序呢
清楚SQL执行顺序以后就能够更加深刻的理解SQL的查询过程和优化的
这个sql 的执行顺序是希望大家都特别的清楚的一个过程,这个过程是是记录了执行不同关键字的时候临时表中的数据的变化情况,知道了临时表的情况以后就可以更明确的理解sql的一些执行和技巧
第一步,执行
关于什么是笛卡尔积,请自行Google补脑。经过FROM语句对两个表执行笛卡尔积,会得到一个虚拟表,暂且叫VT1(vitual table 1),内容如下:
总共有28(table1的记录条数 * table2的记录条数)条记录。这就是VT1的结果,接下来的操作就在VT1的基础上进行。
执行完笛卡尔积以后,接着就进行
VT2就是经过
这一步只有在连接类型为
添加外部行的工作就是在VT2表的基础上添加保留表中被过滤条件过滤掉的数据,非保留表中的数据被赋予NULL值,最后生成虚拟表VT3。
由于我在准备的测试SQL查询逻辑语句中使用的是
现在就把这条数据添加到VT2表中,得到的VT3表如下:
接下来的操作都会在该VT3表上进行。
对添加外部行得到的VT3进行WHERE过滤,只有符合<where_condition>的记录才会输出到虚拟表VT4中。当我们执行
但是在使用WHERE子句时,需要注意以下两点:
由于数据还没有分组,因此现在还不能在WHERE过滤器中使用
由于还没有进行列的选取操作,因此在SELECT中使用列的别名也是不被允许的,如:
得到的内容会存入虚拟表VT5中,此时,我们就得到了一个VT5虚拟表,接下来的操作都会在该表上完成。
这就是虚拟表VT6。
现在才会执行到
我们执行测试语句中的
不,还没有完,这只是虚拟表VT7。
如果在查询中指定了
由于我的测试SQL语句中并没有使用DISTINCT,所以,在该查询中,这一步不会生成一个虚拟表。
对虚拟表中的内容按照指定的列进行排序,然后返回一个新的虚拟表,我们执行测试SQL语句中的
可以看到这是对total_orders列进行降序排列的。上述结果会存储在VT8中。
BY子句一起使用。
MySQL数据库的LIMIT支持如下形式的选择:
表示从第n条记录开始选择m条记录。而很多开发人员喜欢使用该语句来解决分页问题。对于小数据,使用LIMIT子句没有任何问题,当数据量非常大的时候,使用
6
![](http://blog.csdn.net/xihuangwutong/article/details/cid:d79f2410ed0027f758ab22b7c682ed7e)
表连接是关系型数据库的最基本的技能,所以掌握表连接的使用技巧,保证数据的准确性就显的特别的重要。一般情况下我们只要掌握了内连接和左右外连接就能够完成绝大部分的需求
下面的这个列子的左右连接数据都是相同的函数,但是得到的结果是不一样的,千万不要认为连接的结果会是相同的
SELECT * FROM `pigcms_store_createshop` LEFT JOIN pigcms_card_store b ON b.shopid=id LEFT JOIN pigcms_card_details c ON b.card_id=c.card_id WHERE (c.`get_time`>=1464710400 and c.`use_time`<1465747200 )
SELECT * FROM `pigcms_card_details` as a LEFT JOIN `pigcms_card_store` as b ON a.`card_id` = b.`card_id`LEFT JOIN `pigcms_store_createshop` as c on b.`shopid` = c.`id`WHERE (a.`get_time`>=1464710400 and a.`use_time`<1465747200 )
6.1 要清楚 join 条件中的and语句和where条件中的and条件对结果集造成的影响
尤其是在使用左连接总的右表中的字段的个数的是后,影响是会非常大的。这个了解sql执行过程会有个深刻的认识的。
7.多列索引和单列索引
MySQL 一次查询只能使用一个索引
多列索引中要遵循最左前缀的规则name_sex_age组成的多列索引,在使用name,name_sex,name_sex_age这三种情况的时候才会被调用
单列索引,如果分别对name,sex,age建成索引的话,在查询的时候回调用一个最严格的索引
所以如果有多列索引的时候,最左端的字段可以不用再建立一个单列索引
where条件的顺序和查找的时间无关,MySQL的内部优化器会按照最合理的索引顺序来进行查找
8.导入大的SQL文件
max_allowed_packet限制了传递的包的大小
客户端向服务端发送sql的时候是一个单独的数据包
9.order by 的缺点
Mysql在数据小于排序缓冲区的时候使用的是快速排序,内存不够的时候使用的是分块排序,最后聚合
磁盘访问太大,要记录每一次的排序结果
10 小心的使用IN子查询
Mysql不是先查询内层,然后使用IN语句,他是把外层压到内层
select * from A where id IN (select a_id from B where status = 1)
mysql 会转换成select * from A where EXISTS(select * from B where status =1 and id = a_id)
子查询要用到id,id是未知的,所以先执行外层
(摘选自《高性能Mysql》)
11.优化limit
limit的数据较大的时候读取的行数更多,舍弃的行数就多了
使用延迟关联可以提高查询的性能
select id from A INNER JOIN (select id from A order by title limit 50,5) AS b ON a.id = b.id
使用其余的方法缩小查询的范围
如果有主键的where条件
使用where id> 50 limit 5
12.强大的内部函数
使用From_Unixtime(),find_in_set()find_in_set(‘8’,str_replace(‘typeoption’, ‘@’,’,’))
select coun(*),From_unixtime(time, ‘%Y-%m-%d’) from pay_order group by From_unixtime(time, ‘%Y-%m-%d’)case when自己编写存储过程和存储函数
参考:
http://www.jellythink.com/archives/924
参考:http://blog.jobbole.com/100349/
1:硬件,2:网络I/O,3查询时间
查询的时间相关:数据表结构的建立,索引的应用,SQL语句的使用
我们后端工程师能够把握的主要是表结构,索引和SQL语句方面,可以通过工程师的智慧来减小公司的成本,优化用户的体验
目前的计算机系统使用的都是分时系统,可能是一个进程给一个用户提供服务。计算机在不同的进程间快速的切换(针对的是单核的原理),如果一个进程占用了太长的时间,不近会影响进程的排序时间,也会因为保存上下文占用空间的资源。所以优化查询就变的很重要了
2更好的查询:时间和空间使用的更少(内存和磁盘消耗,响应时间)
扫描的行数和返回的行数的比例较小
3.索引的优点
索引能减少服务器扫描数据量
可以帮助服务器避免排序和临时表
可以将随机I/O变为顺序I/O
创建索引的一个基本的判断
count(distinct field) / count(*)
4. B-tree的使用场景
更适合有比较的范围的查询:>,<,between
因为只用叶子节点存储数据,其余的节点存储的是数据的范围值(
比保存在左子树的任何键值都要大比保存在右子树的任何键值都要小
)
使用索引的经验之谈:where条件中,group by中的,表连接中的on判断语句中的都可以根据实际的情况来创建索引
使用的是多列的索引还是单列的索引也要根据实际的情况来判定
5.SQL的执行顺序呢
清楚SQL执行顺序以后就能够更加深刻的理解SQL的查询过程和优化的
这个sql 的执行顺序是希望大家都特别的清楚的一个过程,这个过程是是记录了执行不同关键字的时候临时表中的数据的变化情况,知道了临时表的情况以后就可以更明确的理解sql的一些执行和技巧
(7) SELECT (8) DISTINCT <select_list> (1) FROM <left_table> (3) <join_type> JOIN <right_table> (2) ON <join_condition> (4) WHERE <where_condition> (5) GROUP BY <group_by_list> (6) HAVING <having_condition> (9) ORDER BY <order_by_condition> (10) LIMIT <limit_number>
第一步,执行
FROM语句。我们首先需要知道最开始从哪个表开始的,这就是
FROM告诉我们的。现在有了
<left_table>和
<right_table>两个表,我们到底从哪个表开始,还是从两个表进行某种联系以后再开始呢?它们之间如何产生联系呢?——笛卡尔积
关于什么是笛卡尔积,请自行Google补脑。经过FROM语句对两个表执行笛卡尔积,会得到一个虚拟表,暂且叫VT1(vitual table 1),内容如下:
+-------------+----------+----------+-------------+| customer_id | city | order_id | customer_id |+-------------+----------+----------+-------------+|163 | hangzhou | 1|163 ||9you | shanghai | 1|163 || baidu | hangzhou | 1|163 || tx | hangzhou | 1|163 ||163 | hangzhou | 2|163 ||9you | shanghai | 2|163 || baidu | hangzhou | 2|163 || tx | hangzhou | 2|163 ||163 | hangzhou | 3|9you ||9you | shanghai | 3|9you || baidu | hangzhou | 3|9you || tx | hangzhou | 3|9you ||163 | hangzhou | 4|9you ||9you | shanghai | 4|9you || baidu | hangzhou | 4|9you || tx | hangzhou | 4|9you ||163 | hangzhou | 5|9you ||9you | shanghai | 5|9you || baidu | hangzhou | 5|9you || tx | hangzhou | 5|9you ||163 | hangzhou | 6| tx ||9you | shanghai | 6| tx || baidu | hangzhou | 6| tx || tx | hangzhou | 6| tx ||163 | hangzhou | 7| NULL ||9you | shanghai | 7| NULL || baidu | hangzhou | 7| NULL || tx | hangzhou | 7| NULL |+-------------+----------+----------+-------------+
总共有28(table1的记录条数 * table2的记录条数)条记录。这就是VT1的结果,接下来的操作就在VT1的基础上进行。
执行ON过滤
执行完笛卡尔积以后,接着就进行ON a.customer_id = b.customer_id条件过滤,根据
ON中指定的条件,去掉那些不符合条件的数据,得到VT2表,内容如下:
+-------------+----------+----------+-------------+| customer_id | city | order_id | customer_id |+-------------+----------+----------+-------------+|163 | hangzhou | 1|163 ||163 | hangzhou | 2|163 ||9you | shanghai | 3|9you ||9you | shanghai | 4|9you ||9you | shanghai | 5|9you || tx | hangzhou | 6| tx |+-------------+----------+----------+-------------+
VT2就是经过
ON条件筛选以后得到的有用数据,而接下来的操作将在VT2的基础上继续进行。
添加外部行
这一步只有在连接类型为OUTER JOIN时才发生,如
LEFT OUTER JOIN、
RIGHT OUTER JOIN和
FULL OUTER JOIN。在大多数的时候,我们都是会省略掉
OUTER关键字的,但
OUTER表示的就是外部行的概念。
LEFT OUTER JOIN把左表记为保留表,得到的结果为:
+-------------+----------+----------+-------------+| customer_id | city | order_id | customer_id |+-------------+----------+----------+-------------+|163 | hangzhou | 1|163 ||163 | hangzhou | 2|163 ||9you | shanghai | 3|9you ||9you | shanghai | 4|9you ||9you | shanghai | 5|9you || tx | hangzhou | 6| tx || baidu | hangzhou | NULL | NULL |+-------------+----------+----------+-------------+
RIGHT OUTER JOIN把右表记为保留表,得到的结果为:
+-------------+----------+----------+-------------+| customer_id | city | order_id | customer_id |+-------------+----------+----------+-------------+|163 | hangzhou | 1|163 ||163 | hangzhou | 2|163 ||9you | shanghai | 3|9you ||9you | shanghai | 4|9you ||9you | shanghai | 5|9you || tx | hangzhou | 6| tx || NULL | NULL | 7| NULL |+-------------+----------+----------+-------------+
FULL OUTER JOIN把左右表都作为保留表,得到的结果为:
+-------------+----------+----------+-------------+| customer_id | city | order_id | customer_id |+-------------+----------+----------+-------------+|163 | hangzhou | 1|163 ||163 | hangzhou | 2|163 ||9you | shanghai | 3|9you ||9you | shanghai | 4|9you ||9you | shanghai | 5|9you || tx | hangzhou | 6| tx || baidu | hangzhou | NULL | NULL || NULL | NULL | 7| NULL |+-------------+----------+----------+-------------+
添加外部行的工作就是在VT2表的基础上添加保留表中被过滤条件过滤掉的数据,非保留表中的数据被赋予NULL值,最后生成虚拟表VT3。
由于我在准备的测试SQL查询逻辑语句中使用的是
LEFT JOIN,过滤掉了以下这条数据:
| baidu | hangzhou | NULL | NULL |
现在就把这条数据添加到VT2表中,得到的VT3表如下:
+-------------+----------+----------+-------------+| customer_id | city | order_id | customer_id |+-------------+----------+----------+-------------+|163 | hangzhou | 1|163 ||163 | hangzhou | 2|163 ||9you | shanghai | 3|9you ||9you | shanghai | 4|9you ||9you | shanghai | 5|9you || tx | hangzhou | 6| tx || baidu | hangzhou | NULL | NULL |+-------------+----------+----------+-------------+
接下来的操作都会在该VT3表上进行。
执行WHERE过滤
对添加外部行得到的VT3进行WHERE过滤,只有符合<where_condition>的记录才会输出到虚拟表VT4中。当我们执行WHERE a.city = 'hangzhou'的时候,就会得到以下内容,并存在虚拟表VT4中:
+-------------+----------+----------+-------------+| customer_id | city | order_id | customer_id |+-------------+----------+----------+-------------+|163 | hangzhou | 1|163 ||163 | hangzhou | 2|163 || tx | hangzhou | 6| tx || baidu | hangzhou | NULL | NULL |+-------------+----------+----------+-------------+
但是在使用WHERE子句时,需要注意以下两点:
由于数据还没有分组,因此现在还不能在WHERE过滤器中使用
where_condition=MIN(col)这类对分组统计的过滤;
由于还没有进行列的选取操作,因此在SELECT中使用列的别名也是不被允许的,如:
SELECT city as c FROM t WHERE c='shanghai';是不允许出现的。
执行GROUP BY分组
GROU BY子句主要是对使用
WHERE子句得到的虚拟表进行分组操作。我们执行测试语句中的
GROUP BY a.customer_id,就会得到以下内容:
+-------------+----------+----------+-------------+| customer_id | city | order_id | customer_id |+-------------+----------+----------+-------------+|163 | hangzhou | 1|163 || baidu | hangzhou | NULL | NULL || tx | hangzhou | 6| tx |+-------------+----------+----------+-------------+
得到的内容会存入虚拟表VT5中,此时,我们就得到了一个VT5虚拟表,接下来的操作都会在该表上完成。
执行HAVING过滤
HAVING子句主要和
GROUP BY子句配合使用,对分组得到的VT5虚拟表进行条件过滤。当我执行测试语句中的
HAVING count(b.order_id) < 2时,将得到以下内容:
+-------------+----------+----------+-------------+| customer_id | city | order_id | customer_id |+-------------+----------+----------+-------------+| baidu | hangzhou | NULL | NULL || tx | hangzhou | 6| tx |+-------------+----------+----------+-------------+
这就是虚拟表VT6。
SELECT列表
现在才会执行到SELECT子句,不要以为
SELECT子句被写在第一行,就是第一个被执行的。
我们执行测试语句中的
SELECT a.customer_id, COUNT(b.order_id) as total_orders,从虚拟表VT6中选择出我们需要的内容。我们将得到以下内容:
+-------------+--------------+| customer_id | total_orders |+-------------+--------------+| baidu | 0|| tx | 1|+-------------+--------------+
不,还没有完,这只是虚拟表VT7。
执行DISTINCT子句
如果在查询中指定了DISTINCT子句,则会创建一张内存临时表(如果内存放不下,就需要存放在硬盘了)。这张临时表的表结构和上一步产生的虚拟表VT7是一样的,不同的是对进行DISTINCT操作的列增加了一个唯一索引,以此来除重复数据。
由于我的测试SQL语句中并没有使用DISTINCT,所以,在该查询中,这一步不会生成一个虚拟表。
执行ORDER BY子句
对虚拟表中的内容按照指定的列进行排序,然后返回一个新的虚拟表,我们执行测试SQL语句中的ORDER BY total_orders DESC,就会得到以下内容:
+-------------+--------------+| customer_id | total_orders |+-------------+--------------+| tx | 1|| baidu | 0|+-------------+--------------+
可以看到这是对total_orders列进行降序排列的。上述结果会存储在VT8中。
执行LIMIT子句
LIMIT子句从上一步得到的VT8虚拟表中选出从指定位置开始的指定行数据。对于没有应用ORDER BY的LIMIT子句,得到的结果同样是无序的,所以,很多时候,我们都会看到LIMIT子句会和ORDER
BY子句一起使用。
MySQL数据库的LIMIT支持如下形式的选择:
LIMIT n, m
表示从第n条记录开始选择m条记录。而很多开发人员喜欢使用该语句来解决分页问题。对于小数据,使用LIMIT子句没有任何问题,当数据量非常大的时候,使用
LIMIT n, m是非常低效的。因为LIMIT的机制是每次都是从头开始扫描,如果需要从第60万行开始,读取3条数据,就需要先扫描定位到60万行,然后再进行读取,而扫描的过程是一个非常低效的过程。所以,对于大数据处理时,是非常有必要在应用层建立一定的缓存机制(貌似现在的大数据处理,都有缓存哦)。各位,请期待我的缓存方面的文章哦。
6
表连接是关系型数据库的最基本的技能,所以掌握表连接的使用技巧,保证数据的准确性就显的特别的重要。一般情况下我们只要掌握了内连接和左右外连接就能够完成绝大部分的需求
下面的这个列子的左右连接数据都是相同的函数,但是得到的结果是不一样的,千万不要认为连接的结果会是相同的
SELECT * FROM `pigcms_store_createshop` LEFT JOIN pigcms_card_store b ON b.shopid=id LEFT JOIN pigcms_card_details c ON b.card_id=c.card_id WHERE (c.`get_time`>=1464710400 and c.`use_time`<1465747200 )
SELECT * FROM `pigcms_card_details` as a LEFT JOIN `pigcms_card_store` as b ON a.`card_id` = b.`card_id`LEFT JOIN `pigcms_store_createshop` as c on b.`shopid` = c.`id`WHERE (a.`get_time`>=1464710400 and a.`use_time`<1465747200 )
6.1 要清楚 join 条件中的and语句和where条件中的and条件对结果集造成的影响
尤其是在使用左连接总的右表中的字段的个数的是后,影响是会非常大的。这个了解sql执行过程会有个深刻的认识的。
7.多列索引和单列索引
MySQL 一次查询只能使用一个索引
多列索引中要遵循最左前缀的规则name_sex_age组成的多列索引,在使用name,name_sex,name_sex_age这三种情况的时候才会被调用
单列索引,如果分别对name,sex,age建成索引的话,在查询的时候回调用一个最严格的索引
所以如果有多列索引的时候,最左端的字段可以不用再建立一个单列索引
where条件的顺序和查找的时间无关,MySQL的内部优化器会按照最合理的索引顺序来进行查找
8.导入大的SQL文件
max_allowed_packet限制了传递的包的大小
客户端向服务端发送sql的时候是一个单独的数据包
9.order by 的缺点
Mysql在数据小于排序缓冲区的时候使用的是快速排序,内存不够的时候使用的是分块排序,最后聚合
磁盘访问太大,要记录每一次的排序结果
10 小心的使用IN子查询
Mysql不是先查询内层,然后使用IN语句,他是把外层压到内层
select * from A where id IN (select a_id from B where status = 1)
mysql 会转换成select * from A where EXISTS(select * from B where status =1 and id = a_id)
子查询要用到id,id是未知的,所以先执行外层
(摘选自《高性能Mysql》)
11.优化limit
limit的数据较大的时候读取的行数更多,舍弃的行数就多了
使用延迟关联可以提高查询的性能
select id from A INNER JOIN (select id from A order by title limit 50,5) AS b ON a.id = b.id
使用其余的方法缩小查询的范围
如果有主键的where条件
使用where id> 50 limit 5
12.强大的内部函数
使用From_Unixtime(),find_in_set()find_in_set(‘8’,str_replace(‘typeoption’, ‘@’,’,’))
select coun(*),From_unixtime(time, ‘%Y-%m-%d’) from pay_order group by From_unixtime(time, ‘%Y-%m-%d’)case when自己编写存储过程和存储函数
参考:
http://www.jellythink.com/archives/924
参考:http://blog.jobbole.com/100349/
相关文章推荐
- Host is not allowed to connect to this MySQL server
- MySql创建本地用户和远程用户 并赋予权限
- Ubuntu下Hive配置(MySQL数据库的安装方式)
- mysql高级:数据库优化
- mysql高级:主从复制
- mysql高级:视图
- 惊心的一天Mysql安装之innodb
- mysql高级:权限检查原理
- MySQL添加用户、删除用户与授权
- mysql高级:存储过程
- mysql 的主从复制
- mysql高级:触发器
- mysql高级:表分区
- mysql高级:event触发器
- MySQL绿色版安装教程
- MYSQL order by排序与索引关系总结
- mysql使用硬链接配合truncate 删除2.2T的表 --杨奇龙
- 一、64位windows 安装mysql
- RHEL更新PHP/MYSQL的源
- mysql体系结构