Frage

In unserem Produkt haben wir eine generische Suchmaschine, und versuchen, die Suchleistung optimze. Viele der in den Abfragen verwendeten Tabellen erlauben Nullwerte. Sollten wir unsere Tabelle Redesign Nullwerte für die Optimierung zu verbieten oder nicht?

Unser Produkt ist sowohl auf Oracle und MS SQL Server.

War es hilfreich?

Lösung

In Oracle, NULL Werte werden nicht indiziert, i. e. diese Abfrage:

SELECT  *
FROM    table
WHERE   column IS NULL

wird immer vollständiger Tabellenscan verwenden, da Index, den Sie brauchen nicht die Werte decken.

Mehr als das, diese Abfrage:

SELECT  column
FROM    table
ORDER BY
        column

wird auch Full Table Scan und sortieren für gleichen Grund verwenden.

Wenn Sie Ihre Werte an sich nicht NULL die erlauben, markieren Sie die Spalte als NOT NULL.

Andere Tipps

Eine zusätzliche Antwort etwas mehr Aufmerksamkeit zu David Aldridge Kommentar auf Quassnoi des akzeptierten Antwort zu ziehen.

Die Aussage:

  

Diese Abfrage:

     

SELECT * FROM Tabelle WHERE Spalte   IS NULL

     

wird immer vollständiger Tabellenscan verwenden

ist nicht wahr. Hier ist der Zähler Beispiel eines Index mit einem wörtlichen Wert mit:

SQL> create table mytable (mycolumn)
  2  as
  3   select nullif(level,10000)
  4     from dual
  5  connect by level <= 10000
  6  /

Table created.

SQL> create index i1 on mytable(mycolumn,1)
  2  /

Index created.

SQL> exec dbms_stats.gather_table_stats(user,'mytable',cascade=>true)

PL/SQL procedure successfully completed.

SQL> set serveroutput off
SQL> select /*+ gather_plan_statistics */ *
  2    from mytable
  3   where mycolumn is null
  4  /

  MYCOLUMN
----------


1 row selected.

SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'))
  2  /

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------
SQL_ID  daxdqjwaww1gr, child number 0
-------------------------------------
select /*+ gather_plan_statistics */ *   from mytable  where mycolumn
is null

Plan hash value: 1816312439

-----------------------------------------------------------------------------------
| Id  | Operation        | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |      |      1 |        |      1 |00:00:00.01 |       2 |
|*  1 |  INDEX RANGE SCAN| I1   |      1 |      1 |      1 |00:00:00.01 |       2 |
-----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("MYCOLUMN" IS NULL)


19 rows selected.

Wie Sie sehen können, wird der Index verwendet wird.

Viele Grüße, Rob.

Kurze Antwort: Ja, bedingt

Das Hauptproblem mit Nullwerten und Leistung ist mit Forward-Lookups zu tun.

Wenn Sie eine Zeile in eine Tabelle einfügen, mit Nullwerten, ist es in der natürlichen Seite platziert, die es gehört. Jede Abfrage für diesen Datensatz sucht, wird an der entsprechenden Stelle finden. Einfach so weit ....

... aber lassen Sie sich sagen, dass die Seite füllt, und jetzt ist die Reihe unter den anderen Reihen kuschelt in. Immer noch gut geht ...

... bis die Zeile aktualisiert wird, und der Nullwert enthält jetzt etwas. Die Größe der Reihe hat sich über den Raum zur Verfügung, um es erhöht, so dass die DB-Engine, etwas dagegen zu tun hat.

Die schnellste Sache für den Server ist zu tun, um die Zeile off die Seite in eine andere zu verschieben, und die Zeile des Eintrags mit einem Vorwärtszeiger zu ersetzen. Leider ist dies erfordert eine zusätzliche Lookup, wenn eine Abfrage durchgeführt wird. Man die natürliche Lage der Zeile zu finden, und eine seine aktuelle Position zu finden

die kurze Antwort auf Ihre Frage ist also ja, diese Felder nicht-nullable machen wird die Suchleistung helfen. Dies gilt insbesondere, wenn es passiert oft, dass die Null-Felder in Datensätze werden Sie suchen auf aktualisiert, um nicht-null.

Natürlich gibt es auch andere Strafen (insbesondere I / O, wenn auch in einem kleinen Ausmaß Index Tiefe) in Verbindung mit größeren Datensätzen, und dann mit Ihnen haben Probleme mit der Anwendung nulls in Bereichen disallowing, die sie vom Konzept erfordern, aber hey, das ist eine andere Problem:)

Wenn Sie Ihre Spalte nicht NULL-Werte enthalten ist es am besten diese Spalte NOT NULL zu erklären, der Optimierer der Lage sein, kann effizienten Weg zu nehmen.

Wenn Sie jedoch NULLs in Ihrer Spalte haben Sie nicht viel Auswahl (ein Nicht-Null-Standardwert kann mehr Probleme schaffen als lösen).

Als Quassnoi erwähnt, NULL-Werte nicht in Oracle indiziert sind, oder um genauer zu sein, wird eine Reihe nicht indiziert werden, wenn alle indizierten Spalten NULL sind, bedeutet dies:

  • , die NULL-Werte können potenziell beschleunigen Ihre Forschung, da der Index weniger Zeilen haben
  • Sie können immer noch die Index NULL Zeilen, wenn Sie eine andere NOT NULL-Spalte zum Index hinzufügen oder sogar eine Konstante ist.

Das folgende Skript zeigt einen Weg Index NULL-Werte:

CREATE TABLE TEST AS 
SELECT CASE
          WHEN MOD(ROWNUM, 100) != 0 THEN
           object_id
          ELSE
           NULL
       END object_id
  FROM all_objects;

CREATE INDEX idx_null ON test(object_id, 1);

SET AUTOTRACE ON EXPLAIN

SELECT COUNT(*) FROM TEST WHERE object_id IS NULL;

Ich würde sagen, dass die Prüfung erforderlich ist, aber es ist schön, andere Völker Erfahrungen kennen zu lernen. Nach meiner Erfahrung auf MS SQL Server, können NULL-Werte und verursachen massive Performance-Probleme (Unterschiede). In einem sehr einfachen Test jetzt in 45 Sekunden eine Abfrage Rückkehr gesehen habe ich, wenn nicht null auf den entsprechenden Felder in der Tabelle erstellen Anweisung und über 25 Minuten festgelegt wurde, wo es nicht gesetzt wurde (gab ich auf der Brust an und nahm nur einen Peak bei der geschätzte Abfrageplan).

Die Testdatum sind 1 Million Zeilen x 20 Spalten, die aus 62 zufällig Klein Alpha-Zeichen auf einem i5-3320 normalen HD und 8 GB RAM (SQL Server mit 2 GB) / SQL Server 2012 Enterprise Edition auf Windows 8.1 aufgebaut sind. Es ist wichtig, Zufallsdaten / unregelmäßige Daten verwenden, um die Prüfung einen realistischen „schlechter“ Falles zu machen. In beiden Fällen wurde Tabelle mit zufälligen Daten neu erstellt und neu geladen, die etwa 30 Sekunden auf Datenbankdateien haben, die bereits eine geeignete Menge an freiem Speicherplatz hatten.

select count(field0) from myTable where field0 
                     not in (select field1 from myTable) 1000000

CREATE TABLE [dbo].[myTable]([Field0] [nvarchar](64) , ...

 vs

CREATE TABLE [dbo].[myTable]([Field0] [nvarchar](64) not null,

aus Performance-Gründen hatten beide Tabellenoption DATA_COMPRESSION = Seitensatz und alles andere war ausgefallen. Keine Indizes.

alter table myTable rebuild partition = all with (data_compression = page);

Nicht nulls aufweist, ist eine Voraussetzung für die im Speicher optimierte Tabellen, für die ich nicht speziell aber SQL Server wird natürlich tun, was am schnellsten ist, die in diesem speziellen Fall massiv in Daten für nicht mit Nullen zu sein scheint und nicht mit null auf die Tabelle erstellen.

Jede nachfolgende Abfragen der gleichen Form auf dieser Tabelle Rückkehr in zwei Sekunden, damit ich Standard Standard Statistiken übernehmen würde und möglicherweise mit dem (1,3 GB) Tabelle passen in den Speicher gut funktionieren. d.

select count(field19) from myTable where field19 
                       not in (select field18 from myTable) 1000000

Auf einer Seite nicht mit Nullen ist und nicht mit null Fälle zu behandeln, macht auch Abfragen viel einfachere, kürzere, weniger fehleranfällig und sehr normalerweise schneller. Wenn irgend möglich, am besten nulls im Allgemeinen auf MS SQL Server zumindest zu vermeiden, sofern sie nicht ausdrücklich erforderlich sind und nicht in angemessener Weise aus der Lösung gearbeitet werden.

mit einer neuen Tabelle starten und diese zu 10m Reihen / 13GB taxierte gleiche Abfrage dauert 12 Minuten, die sehr respektabel sind die Hardware und keine Indizes im Einsatz berücksichtigen. Für Informationen Abfrage war vollständig IO gebunden mit IO schwebt zwischen 20 MB / s zu 60 MB / s. Eine Wiederholung der gleichen Abfrage dauerte 9 Minuten.

Nullable Felder können einen großen Einfluss auf die Leistung haben, wenn „NOT IN“ Abfragen zu tun. Da Zeilen mit allen indizierten Felder auf null gesetzt nicht in einem B-Tree-Indizes indiziert sind, Oracle müssen einen vollständigen Tabellenscan tun für null entires zu überprüfen, selbst wenn ein Index vorhanden ist.

Zum Beispiel:

create table t1 as select rownum rn from all_objects;

create table t2 as select rownum rn from all_objects;

create unique index t1_idx on t1(rn);

create unique index t2_idx on t2(rn);

delete from t2 where rn = 3;

explain plan for
select *
  from t1
 where rn not in ( select rn
                     from t2 );

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      | 50173 |   636K|  3162   (1)| 00:00:38 |
|*  1 |  FILTER            |      |       |       |            |          |
|   2 |   TABLE ACCESS FULL| T1   | 50205 |   637K|    24   (5)| 00:00:01 |
|*  3 |   TABLE ACCESS FULL| T2   | 45404 |   576K|     2   (0)| 00:00:01 |
---------------------------------------------------------------------------

Die Abfrage hat für NULL-Werte zu überprüfen, so dass es einen vollständigen Tabellenscan von T2 für jede Zeile in t1 zu tun hat.

Nun

, wenn wir die Felder nicht auf NULL festlegbare machen, kann es den Index verwenden.

alter table t1 modify rn not null;

alter table t2 modify rn not null;

explain plan for
select *
  from t1
 where rn not in ( select rn
                     from t2 );

-----------------------------------------------------------------------------
| Id  | Operation          | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |        |  2412 | 62712 |    24   (9)| 00:00:01 |
|   1 |  NESTED LOOPS ANTI |        |  2412 | 62712 |    24   (9)| 00:00:01 |
|   2 |   INDEX FULL SCAN  | T1_IDX | 50205 |   637K|    21   (0)| 00:00:01 |
|*  3 |   INDEX UNIQUE SCAN| T2_IDX | 45498 |   577K|     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------

Die Frage, ob NULL-Werte verwenden, da sie die Leistung beeinträchtigen ist einer dieser Balanceakte von Datenbank-Design. Sie müssen Geschäftsanforderungen gegen Leistung balancieren.

Nulls sollte verwendet werden, wenn sie gebraucht werden. Zum Beispiel können Sie ein Datum beginnen haben und ein Enddatum in einer Tabelle. Sie würden wissen oft nicht das Enddatum zum Zeitpunkt der Datensatz erstellt. Daher müssen Sie nulls können, ob sie die Leistung beeinträchtigen oder nicht, da die Daten einfach es ist nicht in zu setzen. Wenn jedoch die Daten müssen von den Geschäftsregeln, zu der Zeit da sein der Datensatz erstellt wird, dann sollten Sie nicht zulassen, nulls. Dies würde die Leistung verbessern, macht Codierung etwas einfacher und stellen Sie sicher, dass die Datenintegrität erhalten bleibt.

Wenn Sie vorhandene Daten, die Sie nicht mehr ändern möchten nulls erlauben, dann haben Sie die Auswirkungen dieser Änderung zu berücksichtigen. Erstens wissen Sie, welchen Wert Sie müssen in die Aufzeichnungen setzen, die zur Zeit null sind? Zweitens haben Sie eine Menge Code, der isnull oder coalesce verwendet, die Sie aktualisieren müssen (diese Dinge zu geringer Leistung, wenn Sie also nicht mehr für sie überprüfen müssen, sollten Sie den Code ändern)? Sie benötigen einen Standardwert? Können Sie wirklich ein zuweisen? Wenn nicht ein Teil des Einsatzes oder Update-Code zu brechen, wenn es nicht bedenkt, dass das Feld nicht mehr Null sein kann. Manchmal werden die Leute in schlechten Informationen setzen, damit sie von Nullen loszuwerden. So, jetzt das Preisfeld muss Dezimalwerte und Dinge wie ‚unbekannt‘ enthalten und somit nicht richtig kann ein Dezimal-Datentyp sein und dann muss man zu allen möglichen Längen gehen, um Berechnungen zu tun. Dies führt oft zu Performance-Problemen als schlecht oder schlechter als die null erstellt. PLus müssen Sie durch den gesamten Code gehen und wo auch immer verwendet man einen refernce zum gefeilt null ist oder nicht null sein, müssen Sie umschreiben auszuschließen oder schließen aufgrund der möglichen schlechten Werte jemand becasue die Daten setzen in ist nicht erlaubt sein null.

Ich habe eine Menge Datenimport aus Kundendaten und jedes Mal, wenn wir eine Datei, in den einig Feld erhalten, die NULL-Werte zulassen soll nicht, wir Müll Daten erhalten, die gereinigt werden muss, bevor wir zu unserem System zu importieren. E-Mail ist einer von ihnen. Oft wird die Dateneingabe diesen Wert nicht zu wissen, und es ist in der Regel eine Art von String-Daten, so dass der Benutzer etwas in hier eingeben kann. Wir gehen auf E-Mails zu importieren und finden Dinge „Ich weiß nicht“. Schwer zu versuchen, tatsächlich eine E-Mail senden an: „Ich weiß nicht“. Wenn das System eine gültige E-Mail-Adresse und überprüft für so etwas wie die Existenz eines @ -Zeichens requres, würden wir ‚I@dont.know“ Wie ist Müll Daten wie dies nützlich für die Nutzer der Daten?

Einige der Performance-Probleme mit NULL-Werte sind ein Ergebnis nonsargable Abfragen zu schreiben. Manchmal nur die where-Klausel neu anordnen, anstatt ein notwendiges null beseitigen kann die Leistung verbessern.

Nach meiner Erfahrung NULL ist ein gültiger Wert und bedeutet in der Regel mit „weiß nicht“. Wenn Sie nicht wissen, dann ist es wirklich sinnlos einige Standardwert für die Spalte bilden oder zu versuchen, einige NOT NULL zu erzwingen. NULL geschieht nur ein spezifischer Fall sein.

Die eigentliche Herausforderung für NULL-Werte ist es Retrieval ein wenig kompliziert. Zum Beispiel können Sie nicht sagen, wo Spalten_Name IN (NULL, 'value1', 'value2').

Persönlich, wenn Sie finden viele Ihrer Spalten oder bestimmte Spalten viel NULLs enthalten Ich glaube, Sie könnten Ihr Datenmodell zu überdenken wollen. Vielleicht können diese null-Spalten in ein Kind Tisch gelegt werden? Zum Beispiel: eine Tabelle mit Telefonnummern, wo es Name ist, Homephone, Handy, faxno, worknumber, NOT etc ... Sie können nur eine oder zwei von denen, bevölkern und es wäre es besser Normalisierung

.

Was Sie tun müssen, ist einen Schritt zurück und sehen, wie die Daten zugegriffen werden. Ist dies eine Spalte, die einen Wert haben sollte? Ist dies eine Spalte, die nur einen Wert für bestimmte Fälle hat? Ist dies eine Spalte, die eine Menge abgefragt werden?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top