Гость
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized" / 25 сообщений из 25, страница 1 из 1
15.06.2020, 13:41
    #39969315
Alexander Us
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
Вопрос об использовании временных таблиц в .NET приложении.

Пример:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
 Using cn As New SqlConnection("Server=myServerAddress;Database=myDataBase;Trusted_Connection=True;")

            '1: ad hoc query - создаем таблицу
            Using cm As New SqlCommand("create table #T1(C1 int)", cn)
                cm.ExecuteNonQuery()
            End Using

            '2: ad hoc query - заливаем данные (обычно я делаю это через SqlBulkCopy)
            Using cm As New SqlCommand("insert #T1 select 1 C1 union all select 1", cn)
                cm.ExecuteNonQuery()
            End Using

            '3: parameterized query - делаем какой то запрос с использованием временной таблицы. результат передаем клиенту.
            Using cm As New SqlCommand("select count(*) from #T1 where C1 = 1", cn)
                cm.Parameters.Add("X", SqlDbType.Int).Value = 1
                ret = CInt(cm.ExecuteScalar())
            End Using
        End Using


Запросы 1 и 2 будут выполнены как "ad hoc", а запрс 3 как "parameterized" - с использованием sp_executesql.

Однако, я нигде не нашел, что такое поведение описано в документации.
Если MS когда нибудь изменит поведение SqlCommand так, что запросы 1 и 2 будут упауованы в sp_executesql, то использование временных таблиц из .NET кода станет новозможным, а приложение станет неработоспособным.


Т.е.:
  • Можно ли включать такое использование времменных таблиц в приложение и быть уверенным, что со следующим фреймворком это ещё будет работать?
  • Может ли кто привести "тынц" в документацию на SqlCommand: "ad hoc" vs. "parameterized"?
...
Рейтинг: 0 / 0
15.06.2020, 14:21
    #39969336
Критик
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
Alexander Us,

Интегрируйте всю логику в хранимки, тогда проблем точно не будет.
...
Рейтинг: 0 / 0
15.06.2020, 14:36
    #39969348
Alexander Us
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
Критик
Alexander Us,

Интегрируйте всю логику в хранимки, тогда проблем точно не будет.

Думаю, Вы слишком оптимистичны.

В хранимку конечно можно передать табличный параметер, но для больного объёма данных табличный параметер тормозот жутко.

Для передачи больного объёма данных (как параметра) единственный хороший способ (в смысле быстрый) это использование временной таблицы и заливка в неё балком.
...
Рейтинг: 0 / 0
15.06.2020, 14:43
    #39969356
a_voronin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
Alexander Us,

Между коннекшинами они потеряются.

Используй либо глобальные ##temp, либо постоянные таблицы.
...
Рейтинг: 0 / 0
15.06.2020, 14:48
    #39969360
Alexander Us
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
a_voronin,

- это понятно, поэтому я и использую один коннекшн

- если создание временной таблицы происходит парамеиризорованном запросе (фактически в в sp_executesql) то такая таблица умирает с его окончанием. Что с одним, что с двумя ##.
...
Рейтинг: 0 / 0
15.06.2020, 14:49
    #39969362
a_voronin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
Alexander Us
a_voronin,

- это понятно, поэтому я и использую один коннекшн

- если создание временной таблицы происходит парамеиризорованном запросе (фактически в в sp_executesql) то такая таблица умирает с его окончанием. Что с одним, что с двумя ##.


А набить в StringBuilder одну мегапартянку и запустить одним махом -- не вариант?
...
Рейтинг: 0 / 0
15.06.2020, 14:59
    #39969370
Alexander Us
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
a_voronin,

логика, которую я описал у меня прекрасно работает на "моих" некритичных приложениях.
Но я не знаю, насколько она "кошерна" в том плане, что я не могу явно влиять на то, чтобя запрос выполнялся как ad hoc.

Ещё раз, я делаю так:

В .NET
1) открываем коннекшн
2) создаём временную таблицу ( только ad hoc командой!!! )
3) заливаем в неё кучу данных через SqlBulkCopy
4) выполняем запрос на выборку/изменение с джоином ко временной таблице (этот запрос уже может быть параметризированный)
5) закрываем коннекшн
...
Рейтинг: 0 / 0
15.06.2020, 15:02
    #39969374
Alexander Us
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
a_voronin
...А набить в StringBuilder одну мегапартянку...

Для человека, раз вкусившего скорость, прелесть и удобство SqlBulkCopy, это если и вариант, то с горючими, горючими слезами.
...
Рейтинг: 0 / 0
15.06.2020, 17:02
    #39969463
Alexander Us
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
В исходном коде от MS для SqlCommand написано :

Код: c#
1.
2.
else if ((System.Data.CommandType.Text == this.CommandType) && (0 == GetParameterCount(_parameters))) {
// Send over SQL Batch command if we are not a stored proc and have no parameters



Будет ли это достаточным основанием считать, что так будет и в следующих версиях .Framework?

Модератор: Тема перенесена из форума "Microsoft SQL Server".
...
Рейтинг: 0 / 0
16.06.2020, 09:27
    #39969593
Сон Веры Павловны
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
Alexander Us
Будет ли это достаточным основанием считать, что так будет и в следующих версиях .Framework?

Ни это, ни вообще что-либо не будет достаточным основанием считать, что в следующиих версиях будет и это, и сама SqlCommand, и вообще что угодно. Прецедент с выпиливанием DataTable в Core 1.0 уже был - в 2.0, правда, вернули.
...
Рейтинг: 0 / 0
16.06.2020, 09:53
    #39969607
a_voronin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
Alexander Us

2) создаём временную таблицу ( только ad hoc командой!!! )
3) заливаем в неё кучу данных через SqlBulkCopy
4) выполняем запрос на выборку/изменение с джоином ко временной таблице (этот запрос уже может быть параметризированный)


Вот для такой последовательности действий очень хорошо подходить IN-MEMORY SCHEMA_ONLY.

Чего вы ходите вокруг временной таблицы, непонятно.
...
Рейтинг: 0 / 0
16.06.2020, 11:51
    #39969685
Alexander Us
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
a_voronin
для такой последовательности действий очень хорошо подходить IN-MEMORY SCHEMA_ONLY.
Чего вы ходите вокруг временной таблицы, непонятно.

Дык это для SQL2008 R2 Enterprise :(
Но спасибо за совет, буду иметь ввиду для более новых версий.
...
Рейтинг: 0 / 0
23.06.2020, 13:40
    #39972375
Сон Веры Павловны
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
a_voronin
Вот для такой последовательности действий очень хорошо подходить IN-MEMORY SCHEMA_ONLY.

Чего вы ходите вокруг временной таблицы, непонятно.

Ради интереса проверил:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
USE master
GO
CREATE DATABASE InMemDb CONTAINMENT = NONE
ON PRIMARY (
  NAME = N'InMemDb', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\InMemDb.mdf' ,
  SIZE = 275456KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ), 
FILEGROUP [MEMGROUP] CONTAINS MEMORY_OPTIMIZED_DATA  DEFAULT (
  NAME = N'MemDataFile', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\MemDataFile' ,
  MAXSIZE = UNLIMITED
)
LOG ON (
  NAME = N'InMemDb_log',
  FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\InMemDb_log.ldf' ,
  SIZE = 1341696KB , MAXSIZE = 2048GB , FILEGROWTH = 10%
)
GO

use InMemDb
go
create table dbo.NotInMemory (
  id bigint identity not null primary key nonclustered,
  n int not null,
)
go
create table dbo.InMemory (
  id bigint identity NOT NULL,
  n int not null,
  primary key nonclustered hash (id) with (bucket_count = 1048576)
) with (memory_optimized = on, durability = schema_only)
go
select @@version;


Код: plaintext
1.
2.
3.
Microsoft SQL Server 2014 (SP2-CU12) (KB4130489) - 12.0.5589.7 (X64) 
	Jun  9 2018 11:17:15 
	Copyright (c) Microsoft Corporation
	Developer Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1)

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
public class Program
{
  public static void Main(string[] args)
    => BenchmarkRunner.Run<Program>();

  [Benchmark]
  public void InMemoryInsert()
  {
    using(var cnn = new SqlConnection("Data Source=.;Initial Catalog=InMemDb;Integrated Security=True"))
    {
      cnn.Open();
      using(var tran = cnn.BeginTransaction())
      {
        using(var cmd = new SqlCommand("insert into dbo.InMemory(n) values(@n)", cnn, tran))
        {
          var p = cmd.Parameters.Add("@n", SqlDbType.Int);
          using(var idr = new IntDataReader())
            while(idr.Read())
            {
              p.Value = idr.GetValue(0);
              cmd.ExecuteNonQuery();
            }
        }
        tran.Commit();
      }
    }
  }

  [Benchmark]
  public void BulkInsert()
  {
    using(var cnn = new SqlConnection("Data Source=.;Initial Catalog=InMemDb;Integrated Security=True"))
    {
      cnn.Open();
      using(var bc = new SqlBulkCopy(cnn))
      {
        bc.DestinationTableName = "dbo.NotInMemory";
        bc.ColumnMappings.Add(0, 1);
        using(var idr = new IntDataReader())
          bc.WriteToServer(idr);
      }
    }
  }

  class IntDataReader : IDataReader
  {
    const int MaxValue = 10000;
    public void Close() => RecordsAffected = MaxValue;
    public void Dispose() => Close();
    public bool Read() => RecordsAffected < MaxValue;
    public int FieldCount => 1;
    public int Depth => 0;
    public bool IsClosed => RecordsAffected >= MaxValue;
    public int RecordsAffected { get; private set; }
    public object GetValue(int i) => RecordsAffected++;

    public string GetName(int i) => throw new NotImplementedException();
    public string GetDataTypeName(int i) => throw new NotImplementedException();
    public Type GetFieldType(int i) => throw new NotImplementedException();
    public int GetValues(object[] values) => throw new NotImplementedException();
    public int GetOrdinal(string name) => throw new NotImplementedException();
    public bool GetBoolean(int i) => throw new NotImplementedException();
    public byte GetByte(int i) => throw new NotImplementedException();
    public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
      => throw new NotImplementedException();
    public char GetChar(int i) => throw new NotImplementedException();
    public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
      => throw new NotImplementedException();
    public Guid GetGuid(int i) => throw new NotImplementedException();
    public short GetInt16(int i) => throw new NotImplementedException();
    public int GetInt32(int i) => throw new NotImplementedException();
    public long GetInt64(int i) => throw new NotImplementedException();
    public float GetFloat(int i) => throw new NotImplementedException();
    public double GetDouble(int i) => throw new NotImplementedException();
    public string GetString(int i) => throw new NotImplementedException();
    public decimal GetDecimal(int i) => throw new NotImplementedException();
    public DateTime GetDateTime(int i) => throw new NotImplementedException();
    public IDataReader GetData(int i) => throw new NotImplementedException();
    public bool IsDBNull(int i) => throw new NotImplementedException();
    public object this[int i] => throw new NotImplementedException();
    public object this[string name] => throw new NotImplementedException();
    public DataTable GetSchemaTable() => throw new NotImplementedException();
    public bool NextResult() => throw new NotImplementedException();
  }
}


Результат:

Код: plaintext
1.
2.
3.
         Method |      Mean |     Error |    StdDev |
--------------- |----------:|----------:|----------:|
 InMemoryInsert | 578.86 ms | 5.4307 ms | 5.0799 ms |
     BulkInsert |  66.25 ms | 0.9006 ms | 0.7520 ms |

Я, пожалуй, пока буду пользоваться SqlBulkCopy.
...
Рейтинг: 0 / 0
23.06.2020, 18:04
    #39972519
a_voronin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
Сон Веры Павловны

Я, пожалуй, пока буду пользоваться SqlBulkCopy.


А вы сделали совсем не то, что я рекомендовал

Я имел ввиду попробовать

using(var bc = new SqlBulkCopy(cnn))

1) на физической таблице
2) на InMemory таблице

SqlBulkCopy в обоих случаях.

причем попробуйте в 10 - 15 потоках.
...
Рейтинг: 0 / 0
23.06.2020, 18:10
    #39972520
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
a_voronin
2) на InMemory таблице


А если данных больше чем доступная Memory?
...
Рейтинг: 0 / 0
23.06.2020, 18:23
    #39972522
Сон Веры Павловны
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
a_voronin
1) на физической таблице
2) на InMemory таблице

И как в таком случае быть с конкурентным доступом? В тесте я для простоты использовал постоянную таблицу, но вообще предполагалось, что как и у ТС, заливка будет делаться во временную, которая видна только тому, кто делает заливку. А что будет с in-memory?
...
Рейтинг: 0 / 0
26.06.2020, 17:28
    #39973631
ЕвгенийВ
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
hVostt
a_voronin
2) на InMemory таблице


А если данных больше чем доступная Memory?

А что, если данных больше чем доступно места на дисках?
...
Рейтинг: 0 / 0
26.06.2020, 17:31
    #39973632
ЕвгенийВ
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
Alexander Us
  • Можно ли включать такое использование времменных таблиц в приложение и быть уверенным, что со следующим фреймворком это ещё будет работать?
  • Можно. У них у первых "послетает" куча кода.
    Alexander Us
  • Может ли кто привести "тынц" в документацию на SqlCommand: "ad hoc" vs. "parameterized"?
  • Нет.
    ...
    Рейтинг: 0 / 0
    27.06.2020, 22:39
        #39973823
    hVostt
    Участник
    Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
    Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
    ЕвгенийВ
    hVostt
    пропущено...


    А если данных больше чем доступная Memory?

    А что, если данных больше чем доступно места на дисках?


    Дисковое пространство можно расширить до десятков ТБ очень дёшево.

    Вопрос актуален.
    ...
    Рейтинг: 0 / 0
    28.06.2020, 15:35
        #39973934
    Alexander Us
    Участник
    Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
    Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
    hVostt
    a_voronin
    2) на InMemory таблице


    А если данных больше чем доступная Memory?


    Конечно это зависит от логики Вашего приложения.
    Я обычно использую TempTable в комбинации с SqlBulkcopy для копирования / преобразования данных порциями.
    Так что для меня память не стала бы проблемой.
    ...
    Рейтинг: 0 / 0
    28.06.2020, 15:43
        #39973936
    hVostt
    Участник
    Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
    Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
    Alexander Us
    Конечно это зависит от логики Вашего приложения.
    Я обычно использую TempTable в комбинации с SqlBulkcopy для копирования / преобразования данных порциями.
    Так что для меня память не стала бы проблемой.


    Порции конечно решают... )
    ...
    Рейтинг: 0 / 0
    28.06.2020, 18:05
        #39973953
    Ролг Хупин
    Участник
    Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
    Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
    Alexander Us
    Вопрос об использовании временных таблиц в .NET приложении.

    Пример:
    Код: vbnet
    1.
    2.
    3.
    4.
    5.
    6.
    7.
    8.
    9.
    10.
    11.
    12.
    13.
    14.
    15.
    16.
    17.
    18.
     Using cn As New SqlConnection("Server=myServerAddress;Database=myDataBase;Trusted_Connection=True;")
    
                '1: ad hoc query - создаем таблицу
                Using cm As New SqlCommand("create table #T1(C1 int)", cn)
                    cm.ExecuteNonQuery()
                End Using
    
                '2: ad hoc query - заливаем данные (обычно я делаю это через SqlBulkCopy)
                Using cm As New SqlCommand("insert #T1 select 1 C1 union all select 1", cn)
                    cm.ExecuteNonQuery()
                End Using
    
                '3: parameterized query - делаем какой то запрос с использованием временной таблицы. результат передаем клиенту.
                Using cm As New SqlCommand("select count(*) from #T1 where C1 = 1", cn)
                    cm.Parameters.Add("X", SqlDbType.Int).Value = 1
                    ret = CInt(cm.ExecuteScalar())
                End Using
            End Using
    


    Запросы 1 и 2 будут выполнены как "ad hoc", а запрс 3 как "parameterized" - с использованием sp_executesql.

    Однако, я нигде не нашел, что такое поведение описано в документации.
    Если MS когда нибудь изменит поведение SqlCommand так, что запросы 1 и 2 будут упауованы в sp_executesql, то использование временных таблиц из .NET кода станет новозможным, а приложение станет неработоспособным.


    Т.е.:
    • Можно ли включать такое использование времменных таблиц в приложение и быть уверенным, что со следующим фреймворком это ещё будет работать?
    • Может ли кто привести "тынц" в документацию на SqlCommand: "ad hoc" vs. "parameterized"?

    Что в вашем понимании "следующий фреймворк"?
    ...
    Рейтинг: 0 / 0
    28.06.2020, 20:47
        #39973971
    Alexander Us
    Участник
    Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
    Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
    Ролг Хупин
    Что в вашем понимании "следующий фреймворк"?

    То,что больше 4.8 выпущенной в апреле 2019.
    Хотелось бы, чтобы код сохранил работоспособность и с ними.
    ...
    Рейтинг: 0 / 0
    29.06.2020, 09:02
        #39974058
    Ролг Хупин
    Участник
    Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
    Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
    Alexander Us
    Ролг Хупин
    Что в вашем понимании "следующий фреймворк"?

    То,что больше 4.8 выпущенной в апреле 2019.
    Хотелось бы, чтобы код сохранил работоспособность и с ними.


    Не помню, чтобы такие несовместимости были в новых фреймворках, ну, это ладно.
    "Следующий": В ноябре выдйет 5.0, основанный на Core

    В вашем примере, что означает "parameterized query" и что такое "Х"?

    Код: c#
    1.
    2.
    3.
    4.
    5.
    '3: parameterized query - делаем какой то запрос с использованием временной таблицы. результат передаем клиенту.
                Using cm As New SqlCommand("select count(*) from #T1 where C1 = 1", cn)
                    cm.Parameters.Add("X", SqlDbType.Int).Value = 1
                    ret = CInt(cm.ExecuteScalar())
                End Using
    
    ...
    Рейтинг: 0 / 0
    29.06.2020, 10:49
        #39974087
    Alexander Us
    Участник
    Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
    Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized"
    Ролг Хупин
    В вашем примере, что означает "parameterized query" и что такое "Х"?


    parameterized query:
    имеется ввиду, что объект SqlCommand получит параметры, следовательно, на SQL Server запрос прийдёт упакованный в sp_executesql.

    что такое "Х":
    да, пример корявый.
    Прости имелось ввиду, что запрос, который использует временную таблицу для выборки или актуализации данных, может иметь параметры.
    ...
    Рейтинг: 0 / 0
    Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Временные таблицы и SqlCommand: "ad hoc" vs. "parameterized" / 25 сообщений из 25, страница 1 из 1
    Целевая тема:
    Создать новую тему:
    Автор:
    Найденые пользователи ...
    Разблокировать пользователей ...
    Читали форум (0):
    Пользователи онлайн (0):
    x
    x
    Закрыть


    Просмотр
    0 / 0
    Close
    Debug Console [Select Text]