DDC-2214: extra single quotation in sql when using EntityRepository::findBy #2911

Closed
doctrinebot opened this Issue Dec 26, 2012 · 20 comments

2 participants

@doctrinebot

Jira issue originally created by user scourgen:

I'm using symfony 2.1 with mysql.

I have following code:

$related = 
$this->getDoctrine()->getRepository('MyWebBundle:LineRelated')
->findBy(array('line' => $lines), array('count' => 'DESC'), 20);

that generate the sql like this:

SELECT *
FROM line_related t0 
WHERE t0.line_id IN ('6059', 126352, '5677', '6058') 
ORDER BY t0.count DESC 
LIMIT 20

please notice that the sql has extra single quotation around the number 6059,5677 and 6058. which make the sql very slow.

I did a test, when using single quotation,the sql takes 300ms,when using without single quotation,the sql takes 1 ms.

@doctrinebot

Comment created by @FabioBatSilva:

Hi

Could you please attach your entities or a failing test case ?

Cheers

@doctrinebot

Comment created by scourgen:

sure

LineRelated.php :

class LineRelated
{
    /****
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
     protected $id;

    /****
     * @ORM\ManyToOne(targetEntity="Line", inversedBy="line_related")
     * @ORM\JoinColumn(name="line_id", referencedColumnName="id",nullable=false)
     */
     protected $line;

    /****
     * @ORM\Column(name="line*id*related", type="integer")
     */
    protected $line_related;

    /****
     * @ORM\Column(type="smallint",nullable=false)
     */
     protected $count = 0;

###### get/set etc....... #######

Line.php

class Line
{
    /****
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;
########## blablabla #############

my action:

    public function right*line*relatedAction($line = null, $title='相关线路')
    {

        $lines = $l->getByUser($user, array());
//anyway,$lines is an array,It has several elements,each element is an instance of LineEntity.

        $related = $this->getDoctrine()->getRepository('MyWebBundle:LineRelated')->findBy(array('line' => $lines), array('count' => 'DESC'), 20);
//this findBy function generate the sql which is slow.

        return $related;
    }
@doctrinebot

Comment created by @FabioBatSilva:

Hi,

How did you get this query string ?

Repository#findBy does not quote the values, It uses PDO:bindParam.
so the expected query string should be someting like :

WHERE t0.line_id IN (?, ? ,?) 

I tried to reproduce but in my tests the generated Query binds the parameters as "PDO::PARAM_INT".

I have added a test case.
Could you please can try to change it and make fails.

Cheers

@doctrinebot

Comment created by scourgen:

reproduced :

SELECT t0.id AS id1, t0.line*id_related AS line_id_related2, t0.count AS count3, t0.line_id AS line_id4 FROM line_related t0 WHERE t0.line*id IN ('6059', 4851, '6068', 126352, '6060', '1000000') ORDER BY t0.count DESC LIMIT 20
Parameters: [['6059', 4851, '6068', 126352, '6060', '1000000']] 
[Hide runnable query]
Time: 234.53 ms [   Explain query ]

let me have a look on what's going on

@doctrinebot

Comment created by scourgen:

interesting. I've dump(using ladybugdump) the $lines,and I found out that when the element is a Proxies Object(Object(Proxies__GC_\My\WebBundle\Entity\Line)),then the id of that Object will be with quoted,when the elememt is an Real Entity,then It will be without quote.

for example,in my last comment, the parameters is [['6059', 4851, '6068', 126352, '6060', '1000000']]
the result of dumping $lines is :

array(6)

tell me if you need more information. thanks

@doctrinebot

Comment created by @ocramius:

This may be because $_identifier in proxies ( https://github.com/doctrine/doctrine2/blob/42e83a2716d19eada4f1cd49ece77d5f5229a239/lib/Doctrine/ORM/Proxy/ProxyFactory.php#L383 ) is not necessarily composed by integers. This could be fixed with DCOM-96. I'll add the tests to my development branch and will ping you back tomorrow :)

@doctrinebot

Comment created by scourgen:

thanks

@doctrinebot

Comment created by @ocramius:

I see what is going on here... But this should not be a problem anyway, since they're bound anyway as "PDO::PARAM_INT", as [~fabio.bat.silva] told you.

That's only a problem with the logger showing them as string. PDO will handle the conversion before the value hits the DB as far as I know.

@doctrinebot

Comment created by scourgen:

I can understand your point,but what I don't really get is that the execute time of sql is very long,that explained the quote should be in the sql,not like what you said,that's only a problem with the logger.

@doctrinebot

Comment created by @ocramius:

[~scourgen] can you profile the difference directly in CLI? What about checking the bound parameter type? Are those values bound as INTs in your case?

@doctrinebot

Comment created by scourgen:

@ocramius I wish I could, but I was using doctrine2 with symfony2,So It looks like It will takes some time to simulating all environment and settings that could allow me to reproduced the problem.

but anyway,I will have a try and tell you what happen when I found something.

@doctrinebot

Comment created by @ocramius:

[~scourgen] ok, awaiting your reply then

@doctrinebot

Comment created by scourgen:

I've spent some time on playing with native doctrine2. It took me awhile to setup everything. but I just don't get that how to retrive data with its Proxy ojbect(for example ProxiesCG\My\WebBundle\Entity\Line).

I mean the result of $this->_em->getRepository("something")->findxxx() always return an array of real object. I can't reproduced the situation(#comment-19186) that happens on symfony2+doctrine2.

anyway,I can make sure the problem is real exist,Because the execute time of that slow sql from the tool bar of symfony2 is same as I executed it at mysql cli. If the sql shows up on log with quote but running at mysql without quote,the execute time won't be same(actually It will be much more faster,in my case,20x times,from 2xxms to 10ms).

@doctrinebot

Comment created by @ocramius:

[~scourgen] you can use $em->getReference($className, $identifier) (identifier being a key=>value array) to force proxies.

Give it a try :)

@doctrinebot

Comment created by scourgen:

looks like I reproduced it.

    public function testIssue()
    {   
         $no*used=   $this->_em->getRepository(__NAMESPACE_*. '\DDC2214Line')->findOneById(1);
        $lines=array(
            //$this->*em->getRepository(__NAMESPACE_*. '\DDC2214Line')->findOneById(1),
            $this->*em->getReference(__NAMESPACE_*. '\DDC2214Line',1),
            $this->*em->getReference(__NAMESPACE_*. '\DDC2214Line','2'),
            $this->*em->getReference(__NAMESPACE_*. '\DDC2214Line',3),
        );  
        $logger  = $this->_em->getConnection()->getConfiguration()->getSQLLogger();
        $ids     = array_map(function($r){
            return $r->id;
        }, $this->relatedList);

        //$related = $this->*em->getRepository(__NAMESPACE_* . '\DDC2214LineRelated')->findBy(array('line' => $lines), array('count' => 'DESC'), 20);
        $related = $this->*em->createQuery('select lr from '.__NAMESPACE_* . '\DDC2214LineRelated lr where lr.id in (:ids)')->setParameter('ids',$lines)->getResult();

        $query   = end($logger->queries);
//\Doctrine\Common\Util\Debug::dump($query['params']);

        $this->assertCount(3, $related);
        $this->assertEquals($ids, $query['params'][0]);
        $this->assertEquals(\Doctrine\DBAL\Connection::PARAM*INT*ARRAY, $query['types'][0]);
    }   
}

I use MySql Query log to see what's really happen in database(http://dev.mysql.com/doc/refman/5.5/en/query-log.html)

this is the log from table mysql.general_log

2013-01-08 12:23:44 [root] @ localhost [127.0.0.1]  59  0   Connect root@localhost on doctrine_tests
2013-01-08 12:23:44 root[root] @ localhost [127.0.0.1]  59  0   Query   CREATE TABLE DDC2214Line (id INT AUTO*INCREMENT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode*ci ENGINE = InnoDB
2013-01-08 12:23:44 root[root] @ localhost [127.0.0.1]  59  0   Query   CREATE TABLE DDC2214LineRelated (id INT AUTO*INCREMENT NOT NULL, line_id INT NOT NULL, count SMALLINT NOT NULL, line_id_related INT NOT NULL, INDEX IDX_D31307994D7B7542 (line_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode*ci ENGINE = InnoDB
2013-01-08 12:23:44 root[root] @ localhost [127.0.0.1]  59  0   Query   ALTER TABLE DDC2214LineRelated ADD CONSTRAINT FK*D31307994D7B7542 FOREIGN KEY (line*id) REFERENCES DDC2214Line (id)
2013-01-08 12:23:44 root[root] @ localhost [127.0.0.1]  59  0   Query   START TRANSACTION
2013-01-08 12:23:44 root[root] @ localhost [127.0.0.1]  59  0   Query   INSERT INTO DDC2214Line (id) VALUES (null)
2013-01-08 12:23:44 root[root] @ localhost [127.0.0.1]  59  0   Query   INSERT INTO DDC2214Line (id) VALUES (null)
2013-01-08 12:23:44 root[root] @ localhost [127.0.0.1]  59  0   Query   INSERT INTO DDC2214Line (id) VALUES (null)
2013-01-08 12:23:44 root[root] @ localhost [127.0.0.1]  59  0   Query   INSERT INTO DDC2214LineRelated (count, line*id_related, line*id) VALUES (1, 1, 1)
2013-01-08 12:23:44 root[root] @ localhost [127.0.0.1]  59  0   Query   INSERT INTO DDC2214LineRelated (count, line*id_related, line*id) VALUES (2, 2, 2)
2013-01-08 12:23:44 root[root] @ localhost [127.0.0.1]  59  0   Query   INSERT INTO DDC2214LineRelated (count, line*id_related, line*id) VALUES (3, 3, 3)
2013-01-08 12:23:44 root[root] @ localhost [127.0.0.1]  59  0   Query   COMMIT
2013-01-08 12:23:44 root[root] @ localhost [127.0.0.1]  59  0   Query   SELECT t0.id AS id1 FROM DDC2214Line t0 WHERE t0.id = 1 LIMIT 1
2013-01-08 12:23:44 root[root] @ localhost [127.0.0.1]  59  0   Query   SELECT d0*.id AS id0, d0_.count AS count1, d0_.line_id_related AS line_id_related2, d0_.line_id AS line_id3 FROM DDC2214LineRelated d0_ WHERE d0*.id IN (1, '2', 3)
2013-01-08 12:23:44 root[root] @ localhost [127.0.0.1]  59  0   Quit    

you can see,in database level,the second parameter of last query but two has quote ( (1, '2', 3) )

@doctrinebot

Comment created by @beberlei:

A related Github Pull-Request [GH-247] was opened
doctrine/common#247

@doctrinebot

Comment created by @beberlei:

A related Github Pull-Request [GH-247] was closed
doctrine/common#247

@doctrinebot

Comment created by @ocramius:

Added failing test at #693

@doctrinebot

Comment created by @ocramius:

Added test to prevent regressions at 0a90279

@doctrinebot

Issue was closed with resolution "Fixed"

@Ocramius Ocramius was assigned by doctrinebot Dec 6, 2015
@doctrinebot doctrinebot added this to the 2.4 milestone Dec 6, 2015
@doctrinebot doctrinebot closed this Dec 6, 2015
@doctrinebot doctrinebot added the Bug label Dec 7, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment