same query, two different ways, vastly different performance

谁说胖子不能爱 提交于 2019-12-24 08:19:03

问题


I have a Postgres table with more than 8 million rows. Given the following two ways of doing the same query via DBD::Pg, I get wildly different results.

$q .= '%';

## query 1
my $sql = qq{
    SELECT a, b, c
    FROM t 
    WHERE Lower( a ) LIKE '$q'
};
my $sth1 = $dbh->prepare($sql);
$sth1->execute();

## query 2
my $sth2 = $dbh->prepare(qq{
    SELECT a, b, c
    FROM t  
    WHERE Lower( a ) LIKE ?
});
$sth2->execute($q);

query 2 is at least an order of magnitude slower than query 1... seems like it is not using the indexes, while query 1 is using the index.

Would love hear why.


回答1:


With LIKE expressions, b-tree indexes can only be used if the search pattern is left-anchored, i.e. terminated with %. More details in the manual.
Thanks to @evil otto for the link. This link to the current version.

Your first query provides this essential information at prepare time, so the query planner can use a matching index.

Your second query does not provide any information about the pattern at prepare time, so the query planner cannot use any indexes.




回答2:


I suspect that in the first case the query compiler/optimizer detects that the clause is a constant, and can build an optimal query plan. In the second it has to compile a more generic query because the bound variable can be anything at run-time.




回答3:


Are you running both test cases from same file using same $dbh object? I think reason of increasing speed in second case is that you using prepared statement which is already parsed(but maybe I wrong:)).




回答4:


Ahh, I see - I will drop out after this comment since I don't know Perl. But I would trust that the editor is correct in highlighting the $q as a constant. I'm guessing that you need to concatenate the value into the string, rather than just directly referencing the variable. So, my guess is that if + is used for string concatenation in perl, then use something like:

my $sql = qq{ SELECT a, b, c FROM t WHERE Lower( a ) LIKE ' } + $q + qq{'};

(Note: unless the language is tightly integrated with the database, such as Oracle/PLSQL, you usually have to create a completely valid SQL string before submitting to the database, instead of expecting the compiler to 'interpolate'/'Substitute' the value of the variable.)

I would again suggest that you get the COUNT() of the statements, to make sure that you are comparing apple to apples.




回答5:


I don't know Postgres at all, but I think in Line 7 (WHERE Lower( a ) LIKE '$q' ), $q is actually a constant. It looks like your editor thinks so too, since it is highlighted in red. You probably still need to use the ? for the variable.

To test, do a COUNT(*), and make sure they match - I could be way offbase.



来源:https://stackoverflow.com/questions/9269504/same-query-two-different-ways-vastly-different-performance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!