sql 垃圾收集与清理 php 中的查询

sql garbage collection vs cleaning up queries in php

所以,我制作了一个 php 脚本,它生成以下 SQL 查询:

SELECT * FROM icecream WHERE 
flavor = 'vanilla' AND color = 'purple' AND (quality = 'aaa') 
OR flavor = 'marzipan' AND color = 'purple' AND (quality = 'aaa')  
OR flavor = 'vanilla' AND color = 'purple' AND (quality = 'aaa') 

查询的最后一位和第一位相同。

我觉得这不对,显然我更愿意 运行 像

这样的查询
SELECT * FROM icecream WHERE 
flavor = 'vanilla' AND color = 'purple' AND (quality = 'aaa') 
OR flavor = 'marzipan' AND color = 'purple' AND (quality = 'aaa')

省略最后一行。

在这个例子中看起来不错,但让我们这么说 1. 可能有 23 "OR flavor..." 部分代替 2. 100种不同口味 3. 50种不同的颜色 4. 20 个不同的质量评级。

突然之间,创建一个漂亮的 SQL 查询而不重复请求相同的数据变得更加复杂。

当前 SQL 查询有效。但是我应该清理查询以消除重复,还是应该让 SQL 引擎为我完成?

我的意思是,我可以做到...但这值得吗?一方面,我想传递干净的 SQL 查询,但另一方面,这些事情似乎正是 SQL 引擎真正设计的目的。

有什么建议吗?

好的,我看到的问题是:

1) SQL 引擎会删除重复项吗?

these kinds of things is what an SQL engine really is designed to do

2) 如何不费力地传递干净的查询?

I want to pass clean SQL queries


SQL 是声明性语言。

一个declarative language的意思是你告诉它做什么,它决定怎么做。

在这种情况下,mysql 引擎将接受您的查询并确定如何检索您的数据。作为此过程的一部分,查询解析器应删除查询中的重复项。 (解析器可能不会删除它们,这取决于查询的复杂性和适当的优化)。这样做的缺点是解析时间稍长,但我不认为延迟会很明显,尤其是在具有许多 where 子句的复杂查询中。


您的 php 脚本似乎专注于低层次的抽象。

我最好的猜测是您的脚本获取一些数据并将其转换为字符串,然后重复转换,并使用下一段数据。

此方法的缺点是修改或微调结果对象。转换器不知道在前面的步骤中发生了什么,并且不能轻易地检测和删除重复的行。您需要做的是拥有某种可以帮助采用一些规则并从中构建 sql 查询的对象。 (一个这样的工具是 Zend Db)。


最后,我只想指出,您尝试进行的查询似乎不必要地复杂。

23 "OR flavor..." parts

或者当然,虽然您可能需要进行如此复杂的查询,但复杂的查询有更多的性能会受到影响的区域。检查您要完成的目标并确定是否有更直接的方法来获得它可能更为谨慎。目前我没有足够的信息来查看是否有其他方法。

您可以通过阅读 MySQL 优化器使用 EXPLAIN [EXTENDED] SELECT ... 创建的查询计划来回答您的问题。如果计划相同,那么服务器不仅会认为您的查询在逻辑上是等价的,而且还会在内部将它们缩减为相同的查询。

https://dev.mysql.com/doc/refman/5.7/en/explain.html

您的偏好应该是生成的查询在逻辑上是最优的,而不是做会减少优化器可用选项的事情(通过做一些不受欢迎的事情,比如在 WHERE 中使用列名作为函数参数,以及眼球可调试,不需要小聪明

(a = 1 AND b = 1 AND c = 5) OR
(a = 1 AND b = 1 AND c = 27)

...完全等同于...

(a = 1 AND b = 1) AND (c = 5 OR c = 27)

.....或者...

(a = 1 AND b = 1 AND c IN (5,27))

...优化器将很容易理解这些条件,而不管它们在查询中是如何表达的。生成的计划应该是相同的,因此在生成动态查询时无需偏爱其中一个。 (旧版本的 MySQL 可能不一定处理最后一个,也可能处理前两个,但现在这应该不是问题。)

重要的是,WHERE 当然,作为一个逻辑表达式,从逻辑的角度来看具有确定性的评估优先级,但这与针对每一行的评估顺序不同......理论上,没有对最终表达式的条件求值进行排序的顺序——但是优化器可以自由地实际上以任何看起来正确和最佳的顺序来求值条件,不管它们如何被表达。

基于索引查找,在这里,它可能会选择查找所有 b = 1 行,然后在该集合中查找 c = 5 OR c = 27,最后扫描结果行以查找 a = 1 条件.如果您在列 (b,c) 上有一个索引,可能就是这种情况。在程序意义上没有捷径 - WHERE a = 1 AND b = 1 在逻辑上等同于 WHERE b = 1 AND a = 1.

请注意,您应该在示例查询中使用更多括号,以便 AND/OR 优先级的分组是明确的。服务器当然会做对,但是眼球更容易被欺骗,使眼球明白无误的括号不会对 MySQL 优化器造成任何损害,后者似乎很喜欢它们。