2008-09-18 8 views
17

Czy jest szczególnie źle mieć bardzo, bardzo duże zapytanie SQL z wieloma (potencjalnie nadmiarowymi) klauzulami WHERE?Praktyczne ograniczenie długości zapytań SQL (w szczególności MySQL)

Na przykład, tutaj jest kwerenda Mam wygenerowany z mojej aplikacji internetowej ze wszystko wyłączone, która powinna być jak największa zapytanie o ten program do generowania:

SELECT * 
FROM 4e_magic_items 
INNER JOIN 4e_magic_item_levels 
    ON 4e_magic_items.id = 4e_magic_item_levels.itemid 
INNER JOIN 4e_monster_sources 
    ON 4e_magic_items.source = 4e_monster_sources.id 
WHERE (itemlevel BETWEEN 1 AND 30) 
    AND source!=16 AND source!=2 AND source!=5 
    AND source!=13 AND source!=15 AND source!=3 
    AND source!=4 AND source!=12 AND source!=7 
    AND source!=14 AND source!=11 AND source!=10 
    AND source!=8 AND source!=1 AND source!=6 
    AND source!=9 AND type!='Arms' AND type!='Feet' 
    AND type!='Hands' AND type!='Head' 
    AND type!='Neck' AND type!='Orb' 
    AND type!='Potion' AND type!='Ring' 
    AND type!='Rod' AND type!='Staff' 
    AND type!='Symbol' AND type!='Waist' 
    AND type!='Wand' AND type!='Wondrous Item' 
    AND type!='Alchemical Item' AND type!='Elixir' 
    AND type!='Reagent' AND type!='Whetstone' 
    AND type!='Other Consumable' AND type!='Companion' 
    AND type!='Mount' AND (type!='Armor' OR (false)) 
    AND (type!='Weapon' OR (false)) 
ORDER BY type ASC, itemlevel ASC, name ASC 

wydaje się działać na tyle dobrze, ale nie jest to również szczególnie duży ruch (kilkaset odwiedzin dziennie) i zastanawiam się, czy warto byłoby spróbować zoptymalizować zapytania w celu usunięcia zwolnień i tym podobnych.

+0

1. Dziękuję za odpowiedzi na pytanie, myślę, że rozmiar zapytania nie powinien być dla mnie teraz problemem. 2. Dziękujemy wszystkim za porady dotyczące formatowania SQL. Jestem dla niego nowy i jest wiele sztuczek, których nie znam (np. "Wpisz nie (...)") 3. Podobnie jak dodatek, jest to aplikacja PHP/MySQL – Asmor

+1

Oto przydatne Internetowy formater SQL: http://www.sqlinform.com/ – micahwittman

+0

Kiedy i próbujesz korzystać z witryny, czy wydaje się to powolne? Jeśli jest tylko kilkaset trafień dziennie, to chyba nie można się tym martwić. Czy oczekujesz wzrostu natężenia ruchu? O ile? Jeśli nie masz ochoty na odrobinę czasu, możesz po prostu to zrobić, aby chronić witrynę w przyszłości. Ale czy nadszedł czas, aby programowo znaleźć i usunąć nadmiarowość, która jest większa niż czas potrzebny na uruchomienie zapytania? –

Odpowiedz

19

Czytanie zapytania powoduje, że chcę grać w RPG.

To zdecydowanie nie jest za długo. O ile są dobrze sformatowane, powiedziałbym, że praktyczny limit to około 100 linii. Potem lepiej przerwać podkwerendy w widoki, aby nie wpaść w oczy.

Pracowałem z kilkoma zapytaniami, które mają ponad 1000 wierszy, a to jest trudne do debugowania.

Przy okazji, czy mogę zaproponować wersję ponownie sformatowaną? Ma to głównie na celu wykazanie znaczenia formatowania; Ufam, że będzie to łatwiejsze do zrozumienia.

select * 
from 
    4e_magic_items mi 
,4e_magic_item_levels mil 
,4e_monster_sources ms 
where mi.id = mil.itemid 
    and mi.source = ms.id 
    and itemlevel between 1 and 30 
    and source not in(16,2,5,13,15,3,4,12,7,14,11,10,8,1,6,9) 
    and type not in(
        'Arms' ,'Feet' ,'Hands' ,'Head' ,'Neck' ,'Orb' , 
        'Potion' ,'Ring' ,'Rod' ,'Staff' ,'Symbol' ,'Waist' , 
        'Wand' ,'Wondrous Item' ,'Alchemical Item' ,'Elixir' , 
        'Reagent' ,'Whetstone' ,'Other Consumable' ,'Companion' , 
        'Mount' 
       ) 
    and ((type != 'Armor') or (false)) 
    and ((type != 'Weapon') or (false)) 
order by 
    type asc 
,itemlevel asc 
,name asc 

/* 
Some thoughts: 
============== 
0 - Formatting really matters, in SQL even more than most languages. 
1 - consider selecting only the columns you need, not "*" 
2 - use of table aliases makes it short & clear ("MI", "MIL" in my example) 
3 - joins in the WHERE clause will un-clutter your FROM clause 
4 - use NOT IN for long lists 
5 - logically, the last two lines can be added to the "type not in" section. 
    I'm not sure why you have the "or false", but I'll assume some good reason 
    and leave them here. 
*/ 
+1

W rzeczywistości sprzężenia przyspieszą, szczególnie przy odpowiednich wskaźnikach. Powodem jest, że jeśli wszystkie twoje klauzule są w WHERE, mysql pobierze wszystkie dane, a następnie je odfiltruje; mając na uwadze, że przy odpowiednim złączeniu wybierze tylko potrzebne dane, które mogą być o kilka rzędów wielkości mniejsze - szybsze do filtrowania. – Aeon

+1

Aha, i ... O ile czegoś mi nie brakuje, (type! = 'Armor' OR (false)) będzie oceniał jako prawda lub fałsz, ale w obu przypadkach nie będzie wpływa na zestaw wyników, więc naprawdę nie jest potrzebny. – Aeon

+1

To dlatego, że zbroja (i broń) są dalej filtrowane według typu. Na przykład, jeśli wybrano Cloth and Hide, to brzmiało: (type! = 'Armor' OR (FALSE LUB restrykcje takie jak 'C' LUB ograniczenia takie jak 'H')) Strona po prostu dodaje "lub Ograniczenia jak" cokolwiek " "wewnątrz paren, więc fałsz jest potrzebny. – Asmor

0

Większość baz danych obsługuje procedury składowane, aby uniknąć tego problemu. Jeśli twój kod jest wystarczająco szybki, aby go wykonać i łatwo go odczytać, nie musisz go zmieniać, aby skrócić czas kompilacji.

Alternatywą jest użycie przygotowanych sprawozdań więc masz trafienie tylko raz na połączenia klienta, a następnie przechodzą w jedynie parametry dla każdego wywołania

15

Domyślnie MySQL server 5.0 ograniczeniem jest „1MB”, konfigurowalny do 1 GB.

Jest to skonfigurowane za pomocą ustawienia max_allowed_packet zarówno na kliencie, jak i na serwerze, a ograniczenie efektywne to leasingodawca dwóch.

Ostrzeżenia:

  • Jest wielce prawdopodobne, że ten „pakiet” ograniczenie nie map bezpośrednio do znaków w instrukcji SQL. Z pewnością chcesz uwzględnić kodowanie znaków w kliencie, niektóre metadane pakietów itp.).
0

Zakładam, że masz na myśli przez "wyłączony", że pole nie ma wartości?

Zamiast sprawdzać, czy coś nie jest tym, a także nie jest to itp. Czy nie można po prostu sprawdzić, czy pole ma wartość zerową? Lub ustaw pole "wyłączone" i sprawdź, czy typ lub cokolwiek jest "wyłączone".

1

Z praktycznego punktu widzenia, ogólnie rzecz biorąc, uważam, że każdy SELECT, który kończy się na zapisaniu więcej niż 10 linii (umieszczenie każdej klauzuli/warunku w oddzielnym wierszu) jest zbyt długi, aby można go było łatwo utrzymać. W tym momencie prawdopodobnie powinno to być wykonane jako procedura przechowywana, lub powinienem spróbować znaleźć lepszy sposób na wyrażenie tej samej koncepcji - prawdopodobnie tworząc tabelę pośrednią, aby uchwycić jakiś związek, który wydaje mi się często zadawać.

Twój przebieg może się różnić, a istnieją pewne wyjątkowo długie zapytania, które mają dobry powód. Ale moja zasada to 10 linii.

Przykład (łagodnie niewłaściwe SQL)

SELECT x, y, z 
FROM a, b 
WHERE fiz = 1 
AND foo = 2 
AND a.x = b.y 
AND b.z IN (SELECT q, r, s, t 
      FROM c, d, e 
      WHERE c.q = d.r 
       AND d.s = e.t 
       AND c.gar IS NOT NULL) 
ORDER BY b.gonk 

ten jest prawdopodobnie zbyt duża; optymalizacja zależy jednak w dużej mierze od kontekstu.

Pamiętaj tylko, że im dłuższe i bardziej złożone jest zapytanie, tym trudniej je będzie utrzymać.

3

SELECT @@ global.max_allowed_packet

jest to jedyna prawdziwa granica jest regulowana na serwerze, więc nie ma prawdziwy prosto odpowiedź