• MySQL性能优化


    怎样从MySQL一个数据表中提取一条随机的效率,同一时候要保证效率最高。

    方法一

    这是最原始最直观的语法。例如以下:

    SELECT * FROM foo ORDER BY RAND() LIMIT 1

    当数据表中数据量较小时,此方法可行。但当数据量到达一定程度,比方100万数据或以上。就有非常大的性能问题。

    假设你通过EXPLAIN来分析这个 语句,会发现尽管MySQL通过建立一张暂时表来排序,但因为ORDER BY和LIMIT本身的特性。在排序未完毕之前,我们还是无法通过LIMIT来获取须要的记录。亦即。你的记录有多少条,就必须首先对这些数据进行排序。

    方法二

    看来对于大数据量的随机数据抽取,性能的症结出在ORDER BY上,那么怎样避免?方法二提供了一个方案。



    首先,获取数据表的全部记录数:

    SELECT count(*) AS num_rows FROM foo

    然后,通过相应的后台程序记录下此记录总数(假定为num_rows)。

    然后运行:

    SELECT * FROM foo LIMIT [0到num_rows之间的一个随机数],1

    上面这个随机数的获得能够通过后台程序来完毕。此方法的前提是表的ID是连续的或者自增长的。

    这种方法已经成功避免了ORDER BY的产生。

    方法三

    有没有可能不用ORDER BY。用一个SQL语句实现方法二?能够,那就是用JOIN。

    SELECT * FROM Bar B JOIN (SELECT CEIL(MAX(ID)*RAND()) AS ID FROM Bar) AS m ON B.ID >= m.ID LIMIT 1;

    此方法实现了我们的目的,同一时候,在数据量大的情况下,也避免了ORDER BY所造成的全部记录的排序过程。由于通过JOIN里面的SELECT语句实际上仅仅运行了一次,而不是N次(N等于方法二中的num_rows)。并且, 我们能够在筛选语句上加上“大于”符号。还能够避免由于ID好不连续所产生的记录为空的现象。

    在mysql中查询5条不反复的数据,使用下面:

    SELECT * FROM `table` ORDER BY RAND() LIMIT 5

    就能够了。可是真正測试一下才发现这样效率很低。一个15万余条的库,查询5条数据,竟然要8秒以上

    搜索Google,网上基本上都是查询max(id) * rand()来随机获取数据。

    SELECT *
    FROM `table` AS t1 JOIN (SELECT ROUND(RAND() * (SELECT MAX(id) FROM `table`)) AS id) AS t2
    WHERE t1.id >= t2.id
    ORDER BY t1.id ASC LIMIT 5;

    可是这样会产生连续的5条记录。解决的方法仅仅能是每次查询一条,查询5次。

    即便如此也值得,由于15万条的表,查询仅仅须要0.01秒不到。

    上面的语句採用的是JOIN。mysql的论坛上有人使用

    SELECT *
    FROM `table`
    WHERE id >= (SELECT FLOOR( MAX(id) * RAND()) FROM `table` )
    ORDER BY id LIMIT 1;

    我測试了一下,须要0.5秒,速度也不错。可是跟上面的语句还是有非常大差距。总觉有什么地方不正常。

    于是我把语句改写了一下。

    SELECT * FROM `table`
    WHERE id >= (SELECT floor(RAND() * (SELECT MAX(id) FROM `table`))) 
    ORDER BY id LIMIT 1;

    这下,效率又提高了,查询时间仅仅有0.01秒

    最后。再把语句完好一下。加上MIN(id)的推断。我在最開始測试的时候,就是由于没有加上MIN(id)的推断。结果有一半的时间总是查询到表中的前面几行。
    完整查询语句是:

    SELECT * FROM `table`
    WHERE id >= (SELECT floor( RAND() * ((SELECT MAX(id) FROM `table`)-(SELECT MIN(id) FROM `table`)) + (SELECT MIN(id) FROM `table`))) 
    ORDER BY id LIMIT 1;

    SELECT *
    FROM `table` AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(id) FROM `table`)-(SELECT MIN(id) FROM `table`))+(SELECT MIN(id) FROM `table`)) AS id) AS t2
    WHERE t1.id >= t2.id
    ORDER BY t1.id LIMIT 1;

    最后对这两个语句进行分别查询10次。
    前者花费时间 0.147433 秒
    后者花费时间 0.015130 秒
    看来採用JOIN的语法比直接在WHERE中使用函数效率还要高非常多

  • 相关阅读:
    异步请求与中断 ( XHR,Axios,Fetch对比 )
    界面组件Telerik UI for WPF入门指南 如何在运行时切换主题
    界面控件Telerik UI for WinForms入门指南 使用VS下载新版本
    Web界面开发框架DevExtreme v21.2 增强Data Grid功能
    DevExpress WPF入门指南 运行时生成的POCO视图模型(二)
    DevExpress WPF入门指南 运行时生成的POCO视图模型(三)
    B/S端界面控件DevExtreme ASP.NET MVC入门指南 模板语法(二)
    DevExpress跨平台产品——为.NET 7做好准备
    B/S端界面控件DevExtreme ASP.NET MVC入门指南 模板语法(三)
    UI组件Kendo UI for jQuery数据管理教程 TaskBoard/资源
  • 原文地址:https://www.cnblogs.com/yxwkf/p/5180538.html
Copyright © 2020-2023  润新知