2009-05-16 4 views
11

Eine Anwendung verursacht eine hohe Belastung unserer Sql Server 2005-Datenbank. Wir haben keine Kontrolle über die Anwendung, dass diese Abfrage hundres Mal pro Minute läuft:Unerwarteter Tabellenscan für ID! = ID

select id,col1,col2,col3 from table where id != id 

Notiere die id = id, eine Reihe Bedeutung ist, um sich nicht gleich. Es überrascht nicht, das Ergebnis ist immer keine Zeilen gefunden. Sql Server führt jedoch bei jeder Ausführung dieser Abfrage einen Clustered-Index-Scan-Scan durch!

Die id-Spalte ist definiert als:

varchar(15) not null primary key 

Der Abfrageplan eine große Zahl für „Geschätzte Anzahl der Zeilen“ zeigt. Hat jemand eine Idee, warum Sql Server den Tabellenscan braucht, um das Offensichtliche herauszufinden?

Antwort

2

Nach dem Lesen der Antworten hier und Ihre Änderungen, lassen Sie mich Ihre Optionen zusammenzufassen:

  1. ändern MS SQL Server, diesen Fall zu behandeln
  2. Ändern der Anwendung (im Grunde genommen zu Microsoft Support sprechen) zu vermeiden In diesem Fall, oder tun Sie es anders (im Grunde sprechen Sie mit der Unterstützung der Firma, die die Anwendung gemacht)
  3. Ändern Sie auf etwas anderes als SQL Server (wenn die Anwendung es erlaubt), die diesen Fall behandelt
  4. Wechseln Sie zu einer anderen Anwendung

Keine davon sind gute Lösungen, aber leider sind sie die einzigen, die Sie haben. Sie müssen einen auswählen und mit ihm gehen.

Ich würde zuerst Lösung 2 versuchen, es ist diejenige, die die kürzeste Zeit zur Ausführung benötigen würde/sollte.

Wenn andererseits diese Firma nicht bereit ist, die Anwendung zu ändern, würde ich mit Lösung 4 gehen. Dies ist ein großer Leistungsfehler, und wenn das Unternehmen nicht bereit oder nicht in der Lage ist, dieses Problem zu beheben sich zu fragen, was lauert sonst noch um die nächste Ecke?

+0

Danke für die Zusammenfassung, aber wir werden wahrscheinlich mit Option # 5 gehen: mehr Hardware drauf werfen. Arbeiten an 1 und 2 auch. :) – Andomar

+0

Es dauerte ein paar Monate, aber wir haben endlich einen Entwickler der App auf unserer Website, und er änderte die Anwendung innerhalb einer Stunde zu einer intelligenteren Abfrage. – Andomar

1

Ich weiß nicht, warum ID! = ID in diesem Fall so lange dauert (obwohl "offensichtlich" subjektiv ist - es ist nicht unbedingt eine Optimierung, die ich mir vorstellen würde ... es scheint eine ungewöhnliche Abfrage; a kartesische Join ist schmerzhaft, obwohl). Aber im Allgemeinen, versuchen Sie "where 1 = 0" - oder wenn Sie nur das Schema wollen, vielleicht das etwas riskante SET FMTONLY ON.

Edit: nur sah "Wir kontrollieren nicht die Anwendung, die diese Abfrage Hunderte von Mal pro Minute ausführt" ... hmmm ... das macht es schwierig.

3

Jeder Wert entspricht dem Rest der n-1-Werte. deshalb gibt es eine große Zahl für "Geschätzte Anzahl von Zeilen" zurück. Für das obige Problem ist es besser, nicht in.

Der Artikel hier ist ein guter Zeiger für Ihr Problem. Ich hoffe es hilft dir. http://www.sqlservercentral.com/articles/Performance+Tuning/2924/

+0

Ein Test zeigte, dass die NOT IN-Variante immer noch einen Tabellenscan verursacht. Und wir kontrollieren die App nicht, sodass wir die Abfrage nicht ändern können. – Andomar

4

Ihr größtes Problem ist nicht der Tabellenscan. Die zwei größten Probleme sind:

  • Sie haben eine absolut nutzlose Abfrage 100 Mal pro Minute gegen Ihre Datenbank ausgeführt. Meine Vermutung BTW, ist, dass die Abfrage tatsächlich versucht, die Spaltennamen aus der Tabelle zu erhalten, wie Marc Gravell vorschlägt.
  • und was noch wichtiger ist:

    • Sie haben keine Kontrolle darüber, wer oder was Ihre Datenbank zugreift.
    • Dieses zweite Problem wird vor allem Sie endlose Kopfschmerzen verursachen. Unter der Annahme, dass Sie Teil des Daten-Teams in Ihrer Organisation sind (da Sie derjenige sind, der versucht, dieses Problem zu lösen), sollten Sie wirklich die organisatorischen Änderungen vornehmen, die für Ihre Arbeit notwendig sind.

      Viel Glück!

    +0

    Danke für deine Antwort! Die Abfrage enthält tatsächlich die Spaltennamen, ich werde das in der Frage bearbeiten. Die Organisation würde es nicht kümmern, es sei denn, es wäre ein sichtbares Problem, das es (noch) nicht gibt. – Andomar

    +0

    Sie könnten es immer ein sichtbares Problem machen! –

    +1

    Tom H. hat Recht. Das ist wirklich kein technisches Problem. Es ist ein politisches Problem. Anscheinend halten die Anwendungsentwicklung und QA-Teams es für sinnvoll, diese Abfrage hunderte Male pro Minute auszuführen. Ihre Aufgabe ist es, ihre Meinung darüber zu ändern, damit sie korrigiert werden kann. In diesem Fall müssen Sie die Auswirkungen auf die Leistung und die damit verbundenen Risiken quantifizieren und das Management auf das Problem aufmerksam machen. Sobald es eine Krise ist, wird sich das Management auf das Problem konzentrieren. – spencer7593

    6

    Ich würde diese Abfrage vortäuschen ... abstrahieren weg mit einer Ansicht, und dupe die Abfrage.

    Benennen Sie Ihre vorhandene Tabelle ‚Tabelle‘ auf ‚table_org‘ oder etwas anderes, und eine Ansicht wie folgt erstellen:

    CREATE VIEW table 
    AS 
    SELECT * FROM table_org 
    WHERE id='BOGUSKEY' 
    

    Jetzt sollen Sie Ihren 1-Scan durch die Tabelle auf dem Primärschlüssel erhalten, und Es sollte (wie die ursprüngliche Abfrage) nichts finden. Die Anwendung kennt keine weiseren ...

    +0

    Nett out of the box Denken! Leider enthält die Abfrage echte Daten und andere Abfragen erfordern echte Ergebnisse. Darüber hinaus erstellt die Anwendung eigene Tabellen, und sie verweigert die Ausführung, wenn Sie sie durch eine Ansicht ersetzen. – Andomar

    3

    Ich habe diese Art von Abfrage gesehen.

    Am wahrscheinlichsten bauen die Entwickler WHERE-Klauseln basierend auf Benutzereingaben, aktuellen Einstellungen oder einigen anderen Faktoren. In vielen Fällen, vielleicht in der Standardinstanz, benötigen sie eine WHERE-Klausel, die nur ein Platzhalter ist. Das ist, wenn sie Kriterien wie 'ID! = ID', '1 <> 1' usw.

    Die 'Hunderte von Mal pro Minute' führt mich auch zu der Annahme, dass dies ein fehlgeleiteter Standard Platzhalter ist.

    Manchmal verwenden sie ein Kriterium, das das Gegenteil tut, werden immer als wahr ausgewertet, wenn der Standardfall alle Zeilen erfordert.

    Es ist eine Totale, aber mein Vorschlag wäre zu sehen, ob Sie die Anwendungseinstellungen ändern können und sehen, ob diese Abfrage weggeht. Möglicherweise erhalten Sie eine kleine Ergebnismenge, die jedoch weniger häufig ausgeführt wird und von SQL Server besser verarbeitet wird.

    3

    Sie könnten das SQL Server-Support-Team über diese Abfrage wissen lassen (ID <> ID, wenn die Spalte als Primärschlüssel definiert ist) und den vollständigen Tabellenscan, den es verursacht, und um zu sehen, ob sie es vielleicht möchten Fügen Sie in der Abfrage-Engine eine Optimierung hinzu, um sicherzustellen, dass dies nicht zu einem vollständigen Tabellenscan führt.

    Entweder das, oder sprechen Sie mit dem Support-Team der App, die Sie nicht kontrollieren können.

    BEARBEITEN: Versuchen Sie das TechNet-Forum unter http://social.msdn.microsoft.com/forums/en-US/sqldatabaseengine/threads/, um das Verhalten zu melden.

    +0

    Würdest du eine gute Möglichkeit kennen, dies dem Sql Server Support-Team zu melden? – Andomar

    2

    Haben Sie einen nicht gruppierten Index für die ID-Spalte? Wenn nicht, ist der effizienteste Kurs immer ein CIX-Scan. Versuchen Sie ein NCIX in der ID-Spalte hinzuzufügen - es kann zwar immer noch einen Scan durchführen, aber es wird zumindest ein Scan auf einem sehr kleinen Index sein. Wenn Sie mit SQL Server 2008 arbeiten, können Sie einen gefilterten Index erstellen (WHERE-ID <> ID), und SQL Server verwendet den (leeren) gefilterten Index, um die Abfrage zu erfüllen.

    +0

    Wir haben eine CIX in der ID-Spalte. Wenn ich eine NCIX an (id, col1, col2, col3) anschließe, wird das stattdessen verwendet, was schneller ist! Leider ist col3 ziemlich groß. Wir sind auf 2005, aber wenn wir auf 2008 waren, sehen diese gefilterten Indizes wie eine mögliche Lösung aus. – Andomar

    1

    Da ich mit SQL Server weniger vertraut bin, könnte die folgende Lösung auch für SQL Server gelten.

    In Oracle denke ich, dass Sie das naive SQL austricksen können, indem Sie eine materialisierte Ansicht und das Umschreiben von Abfragen verwenden. Die materialisierte Ansicht enthält keine Zeilen, und das Umschreiben der Abfrage erkennt das SQL und leitet die Abfrage stattdessen in die leere Ansicht um. Die materialisierte Ansicht müsste nie aktualisiert werden, da sie immer leer ist.

    2

    Ich bin fast zu schämen diese Antwort zu unterbreiten, aber im Geiste „wenn nichts vernünftig funktioniert, versuchen Sie die verrückt“ ...

     
        Create a constraint on the table where id = id? 
    

    Die where-Klausel nur die Zeilen Verletzung der Einschränkung zurückkehren konnten von denen es per definitionem keine gibt. Diese zusätzliche (wenn auch redundante) Information kann den Optimierer in Ihrem Fall unterstützen. Es kann die Quadratwurzel von nichts erreichen, aber in Ihrem Fall würde ich es für alle Fälle ausprobieren ...

    +0

    +1 Brilliante Idee, aber hat nicht funktioniert. Es wurde versucht, den Cache des Abfrageplans oder eine Einschränkung für (nicht (id! = Id)) zu leeren, aber es wird weiterhin ein Clustered-Index-Scan durchgeführt. – Andomar

    1

    Sieht für mich aus, als ob Sie ein politisches Problem haben, das sich als technisches Problem tarnt. Sie können viel Zeit und Mühe auf das technische Problem verwenden, aber solange Sie immer wiederholen: "Wir kontrollieren nicht die Anwendung", schließen Sie sich selbst davon ab, politische Optionen zu verfolgen.

    Sie können die App nicht steuern, aber Sie können wahrscheinlich einen Einfluss geltend machen. Informieren Sie alle Beteiligten darüber, wie sich das Verhalten dieser Anwendung auf alle anderen Benutzer auswirkt, die diese Datenbank verwenden (verwenden Sie Diagramme, da Sie diese Meldung schnell an die Verwaltung senden möchten). Und klar sein, es ist ein Problem für den Autor der Anwendung oder Microsoft zu beheben. Das könnte zu einem Druck auf den Autor der App führen, oder es könnte eine "O. K., gut. Kaufen wir eine andere Datenbank für diese Anwendung" Antwort vom Management.

    (Sie werden eine Antwort für die Frage haben wollen, ob Microsoft hat „fixed“ diese in SQL Server 2008)

    +0

    Danke für die Antwort! Ich bin zwar genervt, dass die Top-1-Last diese gefälschte Abfrage ist, aber es ist nicht wirklich ein Problem. Die Datenbank läuft immer noch ziemlich reibungslos. Es gibt auch einige leere RAM-Steckplätze im Server. – Andomar

    1

    Ich vermute, dass SqlServer „wissen“ nicht, dass! = (Sollte sei "<>"?) ist antireflexiv (dh A! = A ist immer falsch) ... es sieht einfach, dass es nicht konstant ist (es hängt von Werten aus einer Ergebniszeile ab) und bringt es daher in das Ergebnis Filter. Also "where id <> id" ist möglicherweise sehr unterschiedlich zu "where 1 <> 1".

    Jetzt könnten sie sicherlich diesen Fall erkennen lassen; aber ich denke, es ist einfach nie auf ihre Prioritätenliste gekommen, weil es irgendwo zwischen "seltsam" und "albern" liegt.

    Ja, die Anwendung tut dies zum kotzen, ich glaube, Sie bereits wissen, dass;)

    +0

    ! = Scheint ein Synonym für <> zu sein. Die Anwendung ist ziemlich nützlich, außer für diesen Scheinaspekt. – Andomar

    0

    gibt es keine Möglichkeit, dies nicht zu machen scannen, können Sie für alles außer 1 Reihe fragen, ist, dass ein Scan. Das Beste, auf das Sie hoffen können, ist, dass die Anwendung diese Abfragen nicht mehr sendet.

    +0

    Die Falschheit der Abfrage könnte Sie zu seiner Bedeutung geblendet haben. Es wird nach "id! = Id" abgefragt: Der Wert der Primärschlüsselspalte ist nicht identisch mit sich selbst. Das Ergebnis ist immer 0 Zeilen. – Andomar

    +0

    @Andomar, duh, ich dachte id! = @id –