【问题标题】:Slow sql statement when using variables使用变量时sql语句慢
【发布时间】:2019-04-27 00:18:41
【问题描述】:

我在 MariaDB 10.1.26 上运行以下 SQL 语句,其中包含约 2.000 行即时结果。

select value, datetime from Schuppen 
where (value = (select min(value) from Schuppen where (measure = 'temp') 
    and datetime between '2018-11-01 00:00:00' and '2018-11-02 00:00:00')) 
and datetime between '2018-11-01 00:00:00' and '2018-11-02 00:00:00';

当我将以下语句与日期时间字段的变量一起使用时,执行大约需要 5.5 秒。

set @startdate = cast('2018-11-01 00:00:00' as datetime);
set @enddate = cast('2018-11-02 00:00:00' as datetime);
select value, datetime from Schuppen 
where (value = (select min(value) from Schuppen where (measure = 'temp') 
    and datetime between @startdate and @enddate)) 
and datetime between @startdate and @enddate;

我拥有的数据行越多,执行语句所需的时间就越长。似乎变量以某种方式改变了语句的行为。

这里有什么问题?

【问题讨论】:

标签: mysql sql performance variables mariadb


【解决方案1】:

我使用 MySQL Workbench,@variables 对于查询/搜索给定属性的不同表非常有用。我遇到了类似的问题。在浏览了不同的线程并尝试了不同的事情之后,当我将@variable 设置为与我正在搜索的表中的列完全相同的类型相同的编码时,它运行良好那个变量。

例如:

SET @keyword = CONVERT(CAST("KEYWORD" AS CHAR(8)) USING ASCII);

在这种情况下,我的表 customer 中的搜索列 cname 是 CHAR(8) 类型并使用 ASCII 编码:

SELECT * FROM CUSTOMERS WHERE cname=@keyword;

如果您有多个要查询的表,其中一个 cname 是 CHAR(10),另一个是 CHAR(8),那么您可以执行以下操作:

SET @keyword = "KEYWORD";
SELECT * FROM CUSTOMERS WHERE cname=CONVERT(CAST(@keyword AS CHAR(8)) USING ASCII);
SELECT * FROM EMPLOYEES WHERE cname=CONVERT(CAST(@keyword AS CHAR(10)) USING ASCII);

【讨论】:

    【解决方案2】:

    问题是查询优化器在使用变量时无法找到合适的索引。这是一个已知问题。

    如果您在两个查询中都使用EXPLAIN,您会看到不同之处。尽量避免不必要的变量。

    对于第一个查询,优化器“看到”选择的值并决定可以完美地使用索引来更有效地满足所选范围。

    对于第二个查询,优化器不知道定义范围的两个值,而是决定退回到 FULL SCAN。

    【讨论】:

    • 可能会影响优化器的一件事是用户定义的变量@var 没有数据类型日期时间。 _ 可以从一组有限的数据类型中为用户变量分配一个值:整数、十进制、浮点、二进制或非二进制字符串,或 NULL 值。_ 请参阅link。变量的使用(改用局部变量)不应影响优化,因为优化器在进行优化时可以看到这些值。另一个可能解释差异的原因是第一个使用的查询缓存。
    • @slaakso 没错,这取决于数据类型和变量的处理方式。 (即使用输出不确定的函数)我仍然认为在大多数情况下避免使用仍然是正确的建议,因为当您将 SQL 查询作为应用程序代码的一部分编写时,通常不需要变量。
    • 感谢您的全面解释。这指向了根本原因。但是如何处理存储过程中的 IN 参数呢?我的计划是创建一个 SP 并将开始和结束日期交给它。最佳实践是在我的应用程序代码中使用硬编码日期构建整个 SQL 语句并避免存储过程,对吗?
    • @AndiGasman 好吧,如果你想要最好的性能,这就是要走的路。即使是准备好的语句也可能导致优化器索引误用。如果你想了解更多,我建议阅读 Markus Winand 的“SQL Performance Explained”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-05
    • 1970-01-01
    • 1970-01-01
    • 2016-05-07
    • 1970-01-01
    相关资源
    最近更新 更多