Welcome to Sign in | Help
in Search

Nelamuriri cu IN

Last post 09-17-2008, 3:06 PM by rsocol. 5 replies.
Sort Posts: Previous Next
  •  09-17-2008, 12:48 PM 5626

    Nelamuriri cu IN

    CREATE TABLE A (ID_A int, Nume varchar(50))

    CREATE TABLE B (ID_B int, ID_A int, Nume varchar(50))

    GO

    INSERT INTO A VALUES(1, 'Test1')

    INSERT INTO A VALUES(2, 'Test1')

    INSERT INTO A VALUES(3, 'Test1')

    INSERT INTO A VALUES(4, 'Test1')

     

    INSERT INTO B VALUES (1, 1, 'TestB1')

    INSERT INTO B VALUES (2, 2, 'TestB1')

    INSERT INTO B VALUES (3, 2, 'TestB1')

    INSERT INTO B VALUES (4, 1, 'TestB1')

    INSERT INTO B VALUES (5, 3, 'TestB1')

    INSERT INTO B VALUES (6, 2, 'TestB1')

    INSERT INTO B VALUES (7, 4, 'TestB1')

    INSERT INTO B VALUES (8, 1, 'TestB1')

    INSERT INTO B VALUES (9, 2, 'TestB1')

    INSERT INTO B VALUES (10, 3, 'TestB1')

    INSERT INTO B VALUES (11, 1, 'TestB1')

    INSERT INTO B VALUES (12, 4, 'TestB1')

    INSERT INTO B VALUES (13, 2, 'TestB1')

    INSERT INTO B VALUES (14, 2, 'TestB1')

    INSERT INTO B VALUES (15, 1, 'TestB1')

    INSERT INTO B VALUES (16, 1, 'TestB1')

    INSERT INTO B VALUES (17, 4, 'TestB1')

    INSERT INTO B VALUES (18, 3, 'TestB1')

    INSERT INTO B VALUES (19, 3, 'TestB1')

    INSERT INTO B VALUES (20, 1, 'TestB1')

    GO

    SELECT B.Nume, A.Nume FROM B JOIN A ON B.ID_A = A.ID_A WHERE A.ID_A IN (1, 3)

     

    Daca va uitati la planul de executie la SELECT o sa vedeti ca pe tabela A face predicatul ID_A = 1 OR ID_A = 3, iar pe tabela B face ID_A >= 1 AND ID_A <= 3. Nu inteleg de ce face range la tabela B, de ce nu e acelasi predicat ca si la A. Daca trimit o lista de id-uri la o procedura si fac cu IN, tabela B va avea de suferit enorm. Stie cineva vreo explicatie?

  •  09-17-2008, 1:01 PM 5628 in reply to 5626

    Re: Nelamuriri cu IN

    Precizeaza si versiunea pe care o folosesti.

    Pe 2000, am 2 "TABLE SCAN" (primul pt. A are un filtru [ A ].[ ID_A ]=1 OR [ A ].[ ID_A ]=3  iar al doilea pt. B fără filtru) plus un "HASH MATCH/INNER JOIN".

    O ipoteza pentru acest comportament ar veni din faptul ca joncţiunea care se execută ulterior ar necesita mai puţine resurse din moment ce A este filtrata dar şi B va fi filtrată.
  •  09-17-2008, 1:18 PM 5629 in reply to 5626

    Re: Nelamuriri cu IN

    Presupun că foloseşti SQL Server 2005. Aşa cum spunea şi Bogdan, SQL Server 2000 nu pune niciun filtru la table scan-ul pe tabela B. În schimb, SQL Server 2005, face o optimizare punând un filtru şi pe tabela B (mai precis "ID_A >=1 AND ID_A <=3").

    În condiţiile date (adică fără niciun index), mi se pare o optimizare inteligentă şi utilă. Sigur, s-ar putea face optimizarea punând acelaşi filtru ca pe tabela A (adică "ID_A=1 OR ID_A=3"), dar probabil că au considerat că ar putea mări excesiv complexitatea planului de execuţie atunci când sunt multe valori în clauza IN, fără să aducă un spor de performanţă semnificativ.

    În orice caz, dacă te preocupă performanţa acestui query, cel mai bun lucru pe care poţi să-l faci este să adaugi PRIMARY KEY-uri şi alţi indecşi (eventual să nu permiţi NULL-uri şi să adaugi şi FOREIGN KEY-uri), creând tabelele astfel:

    CREATE TABLE A (ID_A int PRIMARY KEY, Nume varchar(50) NOT NULL)

    CREATE TABLE B (ID_B int PRIMARY KEY, ID_A int NOT NULL REFERENCES A, Nume varchar(50) NOT NULL)

    CREATE INDEX IX1 ON B (ID_A)
    CREATE INDEX IX2 ON B (ID_A) INCLUDE (Nume)

    Răzvan
  •  09-17-2008, 2:10 PM 5630 in reply to 5629

    Re: Nelamuriri cu IN

    Da, 2005 e versiunea.

    Nu am vrut sa complic sql-ul si sa bag indecsi si relatii pentru ca nu influenteaza cu nimic predicatul in discutie, el ramane. Bineinteles ca selectul va fi mai rapid, apar seekuri si nu scanari. Insa tot nu explica de ce apare acest predicat. Nu m-am gandit nici o clipa la marirea excesiva a complexitatii planului de executie, nici nu vad cum s-ar intampla asta. M-am gandit insa ca prefera sa citeasca o zona continua decat I/O la intamplare (foarte costisitor pentru hdd). Insa se ajunge la extreme: prefera sa citeasca zeci de mii de linii decat sa faca doua I/O la intamplare (asta de exemplu daca dau id-urile 1 si 30.000).

    Nu neaparat performanta e problema, ci faptul ca IN nu e asa de inofensiv Smile

     

  •  09-17-2008, 2:36 PM 5631 in reply to 5630

    Re: Nelamuriri cu IN

    liviu.costea:

    Da, 2005 e versiunea.

    Nu am vrut sa complic sql-ul si sa bag indecsi si relatii pentru ca nu influenteaza cu nimic predicatul in discutie, el ramane. Bineinteles ca selectul va fi mai rapid, apar seekuri si nu scanari. Insa tot nu explica de ce apare acest predicat. Nu m-am gandit nici o clipa la marirea excesiva a complexitatii planului de executie, nici nu vad cum s-ar intampla asta. M-am gandit insa ca prefera sa citeasca o zona continua decat I/O la intamplare (foarte costisitor pentru hdd). Insa se ajunge la extreme: prefera sa citeasca zeci de mii de linii decat sa faca doua I/O la intamplare (asta de exemplu daca dau id-urile 1 si 30.000).

    Nu neaparat performanta e problema, ci faptul ca IN nu e asa de inofensiv Smile

     


    Volumul de date pe care ati realizat acest test este mult prea mic pentru a justifica generalizarea. In momentul acesta tabelele sunt ambele in memorie si el utilizeaza un plan de executie pe care il crede optim pentru aceasta situatie. Pentru tabele care contin volume mari de date, situatie in care apare IO este posibil ca planul de executie sa se schimbe.
  •  09-17-2008, 3:06 PM 5632 in reply to 5630

    Re: Nelamuriri cu IN

    liviu.costea:

    [...] prefera sa citeasca zeci de mii de linii decat sa faca doua I/O la intamplare (asta de exemplu daca dau id-urile 1 si 30.000). [...]



    Dacă ar exista indecşi, nu mai face table scan şi hash join, ci ar face index seek şi nested loops, deci ar citi doar rândurile relevante.

    Dacă nu există indecşi, oricum citirea a două rânduri înseamnă citirea întregii tabele.

    Răzvan
View as RSS news feed in XML
Powered by Community Server (Commercial Edition), by Telligent Systems