Как быстро выбрать ОТЛИЧНЫЕ даты из поля Date/Time, SQL Server

После работы в среде, которая имела очень определенные и очень бессмысленные правила стиля с тех пор, я продолжал создавать свой собственный стиль. Это - один тип, на котором я зеркально отразил назад и вперед много. Я наконец решил, что частные поля всегда будут _field, локальные переменные никогда не будут иметь _ и будут нижним регистром, имена переменной для средств управления будут свободно следовать за Венгерской записью, и параметры обычно будут Camel-регистром.

я ненавижу this. ключевое слово, оно просто добавляет слишком много шума кода, по-моему. Я люблю Resharper, удаляют избыточный это. ключевое слово.

6-летнее обновление: я анализировал внутренности Dictionary<TKey,T> для определенного использования параллельного доступа и неправильно читал частное поле, чтобы быть локальной переменной. Частные поля определенно не должны быть тем же соглашением о присвоении имен как локальные переменные. Если бы было подчеркивание, то это было бы невероятно очевидно.

8
задан Community 23 May 2017 в 12:30
поделиться

8 ответов

Каждая опция, которая включает манипуляции CAST, TRUNCATE или DATEPART в поле datetime, имеет одну и ту же проблему: запрос должен сканировать весь набор результатов (40k), чтобы найти отдельные даты. Производительность может незначительно отличаться между различными реализациями.

Что вам действительно нужно, так это иметь индекс, который может мгновенно дать ответ. У вас может быть либо постоянный вычисляемый столбец с индексом, который (требует изменения структуры таблицы), либо индексированное представление ( требуется Enterprise Edition для QO, чтобы учесть индекс из коробки).

Постоянный вычисляемый столбец:

alter table foo add date_only as convert(char(8), [datetimecolumn], 112) persisted;
create index idx_foo_date_only on foo(date_only);

Индексированное представление:

create view v_foo_with_date_only
with schemabinding as 
select id
    , convert(char(8), [datetimecolumn], 112) as date_only
from dbo.foo;   
create unique clustered index idx_v_foo on v_foo_with_date_only(date_only, id);

Обновление

Чтобы полностью исключить сканирование, можно использовать индексированное представление с обманом GROUP BY, например:

create view v_foo_with_date_only
with schemabinding as 
select
    convert(char(8), [d], 112) as date_only
    , count_big(*) as [dummy]
from dbo.foo
group by convert(char(8), [d], 112)

create unique clustered index idx_v_foo on v_foo_with_date_only(date_only)

Запрос выберите отдельный date_only из foo вместо этого будет использовать это индексированное представление. Технически это все еще сканирование, но по уже «отдельному» индексу, поэтому сканируются только необходимые записи. Я считаю, что это хитрость, я бы не рекомендовал ее для реального производственного кода.

AFAIK SQL Server не имеет возможности сканировать истинный индекс с пропуском повторов, т.е. ищите вершину, затем ищите больше вершины, затем последовательно ищите больше последней найденной.

6
ответ дан 5 December 2019 в 05:45
поделиться

Я использовал следующее:

CAST(FLOOR(CAST(@date as FLOAT)) as DateTime);

Это удаляет время из даты, преобразовывая его в float и обрезая "временная" часть,

9
ответ дан 5 December 2019 в 05:45
поделиться

Самый простой способ - добавить вычисляемый столбец только для части даты и выбрать его. Вы можете сделать это в представлении, если не хотите изменять таблицу.

3
ответ дан 5 December 2019 в 05:45
поделиться

нос будет прерван только при первом сбое, если вы передадите параметр -x в командной строке.

test.py:

def test1():
    assert False

def test2():
    assert False

без параметра -x :

C:\temp\py>C:\Python26\Scripts\nosetests.exe test.py
FF
======================================================================
FAIL: test.test1
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Python26\lib\site-packages\nose-0.11.1-py2.6.egg\nose\case.py", line
183, in runTest
    self.test(*self.arg)
  File "C:\temp\py\test.py", line 2, in test1
    assert False
AssertionError

======================================================================
FAIL: test.test2
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Python26\lib\site-packages\nose-0.11.1-py2.6.egg\nose\case.py", line
183, in runTest
    self.test(*self.arg)
  File "C:\temp\py\test.py", line 5, in test2
    assert False
AssertionError

----------------------------------------------------------------------
Ran 2 tests in 0.031s

FAILED (failures=2)

с параметром -x:

C:\temp\py>C:\Python26\Scripts\nosetests.exe test.py -x
F
======================================================================
FAIL: test.test1
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Python26\lib\site-packages\nose-0.11.1-py2.6.egg\nose\case.py", line
183, in runTest
    self.test(*self.arg)
  File "C:\temp\py\test.py", line 2, in test1
    assert False
AssertionError

----------------------------------------------------------------------
Ran 1 test in 0.047s

FAILED (failures=1)

Вы можете рассмотреть возможность просмотра документации носа .

WITH    rows AS (
        SELECT  CAST(CAST(CAST(MIN(date) AS FLOAT) AS INTEGER) AS DATETIME) AS mindate, MAX(date) AS maxdate
        FROM    mytable
        UNION ALL
        SELECT  mindate + 1, maxdate
        FROM    rows
        WHERE   mindate < maxdate
        )
SELECT  mindate
FROM    rows
WHERE   EXISTS
        (
        SELECT  NULL
        FROM    mytable
        WHERE   date >= mindate
                AND date < mindate + 1
        )
OPTION  (MAXRECURSION 0)

Это будет более эффективно, чем Stream Aggregate

2
ответ дан 5 December 2019 в 05:45
поделиться

Каков ваш предикат для этого другого отфильтрованного столбца? Пробовали ли вы улучшить индекс этого другого отфильтрованного столбца, за которым следует поле datetime?

Я в основном предполагаю, но 5 секунд, чтобы отфильтровать набор из 100000 строк до 40000, а затем выполнить sort (что, по-видимому, и происходит) мне не кажется необоснованным. Почему ты говоришь, что это слишком медленно? Потому что это не соответствует ожиданиям?

0
ответ дан 5 December 2019 в 05:45
поделиться

Просто преобразуйте дату: dateadd (dd, 0, datiff (dd, 0, [Some_Column]))

0
ответ дан 5 December 2019 в 05:45
поделиться

Если вы хотите избежать поэтапного извлечения или переформатирования даты - что, по-видимому, является основной причиной задержки (путем принудительного полного сканирования таблицы) - у вас нет альтернативы, кроме как сохранить date - это только часть даты и времени, что, к сожалению, потребует изменения структуры базы данных.

Если вы используете SQL Server 2005 или более поздней версии, то можно использовать постоянное вычисляемое поле

Unless otherwise specified, computed columns are virtual columns that are
not physically stored in the table. Their values are recalculated every 
time they are referenced in a query. The Database Engine uses the PERSISTED 
keyword in the CREATE TABLE and ALTER TABLE statements to physically store 
computed columns in the table. Their values are updated when any columns 
that are part of their calculation change. By marking a computed column as 
PERSISTED, you can create an index on a computed column that is deterministic
but not precise. 
0
ответ дан 5 December 2019 в 05:45
поделиться

Я не уверен, почему ваш существующий запрос займет более 5 секунд для 40 000 строк.

Я только что попробовал следующий запрос к таблице со 100 000 строками, и он вернул менее 0,1 секунды.

SELECT DISTINCT DATEADD(day, 0, DATEDIFF(day, 0, your_date_column))
FROM your_table

(Обратите внимание, что этот запрос, вероятно, не будет иметь возможность использовать любые индексы в столбце даты, но это должно быть достаточно быстро, если предположить, что вы не выполняете его десятки раз в секунду.)

3
ответ дан 5 December 2019 в 05:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: