sql >> Database >  >> RDS >> Sqlserver

SQL Server TUSSEN

Een manier bedenken om BETWEEN te gebruiken met de tabel zoals deze is, zal werken, maar zal in elk geval slechtere prestaties opleveren:

  • Het zal in het beste geval meer CPU verbruiken om een ​​of andere berekening op de rijen uit te voeren in plaats van ermee te werken als datums.
  • Het zal in het ergste geval een tabelscan forceren op elke rij in de tabel, maar als uw kolommen indexen hebben, dan is met de juiste zoekopdracht een zoekopdracht mogelijk. Dit kan een ENORM prestatieverschil zijn, omdat het forceren van de beperkingen in een BETWEEN-clausule het gebruik van de index zal uitschakelen.

Ik stel in plaats daarvan het volgende voor als je een index op je datumkolommen hebt en je je druk maakt om prestaties:

DECLARE
   @FromDate date = '20111101',
   @ToDate date = '20120201';

SELECT *
FROM dbo.YourTable T
WHERE
   (
      T.[Year] > Year(@FromDate)
      OR (    
         T.[Year] = Year(@FromDate)
         AND T.[Month] >= Month(@FromDate)
      )
   ) AND (
      T.[Year] < Year(@ToDate)
      OR (
         T.[Year] = Year(@ToDate)
         AND T.[Month] <= Month(@ToDate)
      )
   );

Het is echter begrijpelijk dat u een dergelijke constructie niet wilt gebruiken, omdat het erg onhandig is. Dus hier is een compromisquery, die op zijn minst numerieke berekeningen gebruikt en minder CPU zal gebruiken dan de berekening van de datum-naar-tekenreeks-conversie (hoewel niet genoeg minder om de geforceerde scan te compenseren, wat het echte prestatieprobleem is).

SELECT *
FROM dbo.YourTable T
WHERE
   T.[Year] * 100 + T.[Month] BETWEEN 201111 AND 201202;

Als u een index heeft op Year , kunt u een grote boost krijgen door de vraag als volgt in te dienen, die de mogelijkheid heeft om te zoeken:

SELECT *
FROM dbo.YourTable T
WHERE
   T.[Year] * 100 + T.[Month] BETWEEN 201111 AND 201202
   AND T.[Year] BETWEEN 2011 AND 2012; -- allows use of an index on [Year]

Hoewel dit uw vereiste om een ​​enkele BETWEEN . te gebruiken, overtreedt uitdrukking, het is niet te veel pijnlijker en zal zeer goed presteren met het Year index.

U kunt ook uw tafel wijzigen. Eerlijk gezegd is het niet goed om afzonderlijke getallen te gebruiken voor uw datumdelen in plaats van een enkele kolom met een datumgegevenstype. De reden dat het niet goed is, is vanwege het exacte probleem waarmee u op dit moment wordt geconfronteerd - het is erg moeilijk te achterhalen.

In sommige datawarehousing-scenario's waar het opslaan van bytes erg belangrijk is, kan ik me situaties voorstellen waarin je de datum als een getal kunt opslaan (zoals 201111 ) maar dat is niet aan te raden. De beste oplossing is om uw tabel te wijzigen om datums te gebruiken in plaats van de numerieke waarde van de maand en het jaar op te splitsen. Sla gewoon de eerste dag van de maand op, in het besef dat deze de hele maand blijft staan.

Als het wijzigen van de manier waarop u deze kolommen gebruikt geen optie is, maar u uw tabel nog steeds kunt wijzigen, kunt u een persistente berekende kolom toevoegen:

ALTER Table dbo.YourTable
   ADD ActualDate AS (DateAdd(year, [Year] - 1900, DateAdd(month, [Month], '18991201')))
   PERSISTED;

Hiermee kun je gewoon doen:

SELECT *
FROM dbo.YourTable
WHERE
   ActualDate BETWEEN '20111101' AND '20120201';

De PERSISTED trefwoord betekent dat hoewel u nog steeds een scan krijgt, deze geen berekening op elke rij hoeft uit te voeren, aangezien de uitdrukking op elke INSERT of UPDATE wordt berekend en in de rij wordt opgeslagen. Maar je kunt krijg een zoekopdracht als u een index aan deze kolom toevoegt, waardoor deze zeer goed presteert (hoewel al met al is dit nog steeds niet zo ideaal als het gebruik van een echte datumkolom, omdat dit meer ruimte in beslag zal nemen en INSERT's zal beïnvloeden en UPDATE's):

CREATE NONCLUSTERED INDEX IX_YourTable_ActualDate ON dbo.YourTable (ActualDate);

Samenvatting:als je de tabel echt op geen enkele manier kunt veranderen, dan zul je op de een of andere manier een compromis moeten sluiten. Het is niet mogelijk om de eenvoudige syntaxis te krijgen die u wilt en die ook goed presteert, wanneer uw datums worden opgesplitst in afzonderlijke kolommen.



  1. MySQL en JDBC met rewriteBatchedStatements=true

  2. Permissies vereist voor 'CREATE USER' in SQL Server 2005?

  3. INSERT INTO SELECT * voor SQL Server, niet mogelijk, heb ik het juist?

  4. Primaire sleutel samenvoegen en bijwerken