Разве соединение не совпадает с сеансом? - PullRequest
0 голосов
/ 22 января 2019

Я пытаюсь понять, когда создаются и удаляются временные таблицы.

Я думал, что временная таблица удаляется в конце сеанса, но этот тест заставляет меня не уверен в этом.

Строка подключения имеет Pooling=true;Maximum Pool Size=50, поэтому существует пул, с максимум 50 подключениями.

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

using (var connection = new NpgsqlConnection(connectionString))
{
    var insertIds = GetInsertIds(1000).ToList();

    await connection.OpenAsync();

    var transaction = connection.BeginTransaction();

    await connection.ExecuteAsync(@"
        CREATE TEMP TABLE tmp_data
        (
            insertid INTEGER NOT NULL
        );", transaction: transaction);

    const string copyItemSql = @"
        COPY tmp_data(
            insertid
        ) FROM STDIN (FORMAT BINARY)
    ";

    using (var writer = connection.BeginBinaryImport(copyItemSql))
    {
        foreach (var insertId in insertIds)
        {
            writer.StartRow();
            writer.Write(insertId, NpgsqlDbType.Integer);
        }
    }

    await connection.ExecuteAsync(@"
        INSERT INTO data (insertid)
            SELECT tmpd.insertid
            FROM tmp_data tmpd;
    ", transaction: transaction);

    transaction.Commit();
}

Мои предположения, где это:

  1. Я бы получил исключение, когда соединение берется из пула и используется повторно, поскольку tmp_data уже существует. Этого не происходит, код работает просто отлично.
  2. Я мог бы обойти это, выполнив CREATE TEMP TABLE IF NOT EXISTS tmp_data .... Но тогда у меня возникнет проблема, что, поскольку tmp_data уже существует, все равно будут строки из предыдущей вставки. И я мог бы обойти это, выполнив ON COMMIT DELETE ROWS.

Так я не прав? Разве соединение в пуле - это не то же самое, что сеанс? Почему временная таблица не существует во второй раз, когда соединение повторно используется?

1 Ответ

0 голосов
/ 22 января 2019

Я посмотрел на реализацию Npgsql, и это то, что работает, когда соединение возвращается в пул:

void GenerateResetMessage()
{
    var sb = new StringBuilder("SET SESSION AUTHORIZATION DEFAULT;RESET ALL;");
    var responseMessages = 2;
    if (DatabaseInfo.SupportsCloseAll)
    {
        sb.Append("CLOSE ALL;");
        responseMessages++;
    }
    if (DatabaseInfo.SupportsUnlisten)
    {
        sb.Append("UNLISTEN *;");
        responseMessages++;
    }
    if (DatabaseInfo.SupportsAdvisoryLocks)
    {
        sb.Append("SELECT pg_advisory_unlock_all();");
        responseMessages += 2;
    }
    if (DatabaseInfo.SupportsDiscardSequences)
    {
        sb.Append("DISCARD SEQUENCES;");
        responseMessages++;
    }
    if (DatabaseInfo.SupportsDiscardTemp)
    {
        sb.Append("DISCARD TEMP");
        responseMessages++;
    }

    responseMessages++;  // One ReadyForQuery at the end

    _resetWithoutDeallocateMessage = PregeneratedMessage.Generate(WriteBuffer, QueryMessage, sb.ToString(), responseMessages);
}

NpgsqlDatabaseInfo.SupportsDiscardTemp устанавливается следующим образом:

public virtual bool SupportsDiscardTemp => Version >= new Version(8, 3, 0);

Таким образом, вы получаете такое поведение всякий раз, когда используете версию PostgreSQL по крайней мере 8.3.

Вы можете избежать этого сброса, используя параметр строки соединения No Reset On Close=true, как прокомментировано Шей Рожански ниже, но тогда вы сами должны позаботиться о том, чтобы оставить сеанс & ldquo; clean & rdquo;.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...