squarecloudlabs/snowflake-laravel-driver

Laravel的Snowflake数据库驱动。

dev-main 2023-03-31 03:42 UTC

This package is auto-updated.

Last update: 2024-09-30 02:10:44 UTC


README

Latest Stable Version Total Downloads License PHP Version Require Github Actions status image

此仓库包含一个Laravel的Snowflake驱动。此驱动封装了Laravel官方的MySQL支持,以便更好地与Snowflake一起使用。具体来说,此驱动相较于原始Laravel MySQL支持具有以下优势

  • 扩展Eloquent,允许通过Eloquent API指定特定的Snowflake功能。有关支持的特性,请参见迁移。@todo
  • 针对PHP和Laravel版本矩阵对Snowflake进行集成测试。@todo
  • 支持JSON列 @todo
  • 查询生成中的其他兼容性修复 @todo

目录

安装

此包处于alpha开发阶段,使用版本dev-main

您可以通过composer安装此包

composer require squarecloudlabs/snowflake-laravel-driver:dev-main

此包需要安装pdo_mysql。如果您不确定,请在运行php -i时检查是否列出了pdo_mysql

使用方法

要启用驱动,请转到您的config/database.php文件,并在connections中为SingleStore创建一个新条目,并将您的default更新为指向该新连接

[
    'default' => env('DB_CONNECTION', 'snowflake'),

    'connections' => [
        'snowflake' => [
            'driver' => 'snowflake',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST'),
            'port' => env('DB_PORT'),
            'database' => env('DB_DATABASE'),
            'username' => env('DB_USERNAME'),
            'password' => env('DB_PASSWORD'),
            'unix_socket' => env('DB_SOCKET'),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
                PDO::ATTR_EMULATE_PREPARES => true,
            ]) : [],
        ],
    ]
]

Snowflake驱动是MySQL驱动的扩展,因此您也可以将drivermysql更改为singlestore

如果您想将失败的任务存储在SingleStore中,那么请确保您也在config/queue.php文件中将它设置为database。在这种情况下,您可能更喜欢在环境变量中设置DB_CONNECTION='singlestore'

'failed' => [
    'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
    'database' => env('DB_CONNECTION', 'singlestore'),
    'table' => 'failed_jobs',
],

连接SingleStore托管服务的问题

如果您遇到连接到SingleStore托管服务的问题,可能是由于您的环境无法验证用于保护连接的SSL证书。您可以通过下载并手动指定SingleStore证书文件来修复此问题。

  • 在此处下载文件
  • 在Laravel SingleStore连接配置中,将变量PDO::MYSQL_ATTR_SSL_CA指向singlestore_bundle.pem
'options' => extension_loaded('pdo_mysql') ? array_filter([
    PDO::MYSQL_ATTR_SSL_CA => 'path/to/singlestore_bundle.pem',
    PDO::ATTR_EMULATE_PREPARES => true,
]) : [],

持久连接(性能优化)

通常,我们建议在连接到SingleStoreDB时启用PDO::ATTR_PERSISTENT。这是因为与运行许多事务性查询相比,打开新的SingleStoreDB连接非常昂贵。通过使用PDO::ATTR_PERSISTENT,您可以极大地提高事务性工作负载的性能。

使用持久连接的唯一缺点是需要确保事务正确清理,以及在使用会话变量或上下文数据库时要小心。您可以在php.net的官方文档中了解更多关于此功能的信息

此外,请注意,SingleStoreDB在其默认配置下可以处理非常大的空闲连接数量,而不会影响性能。默认情况下,每个聚合器大约有100,000个空闲连接,但如果您的服务器可以处理,这个数字可以设置得更高。

要启用此功能,只需更新您的选项以包括 PDO::ATTR_PERSISTENT => true

'options' => extension_loaded('pdo_mysql') ? array_filter([
    PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
    PDO::ATTR_EMULATE_PREPARES => true,
    PDO::ATTR_PERSISTENT => true,
]) : [],

8.1之前的PHP版本

在 PHP 8.1 版本之前的版本中,标志 PDO::ATTR_EMULATE_PREPARES 会导致一个历史已知错误,即 MySQL(和 SingleStoreDB)返回的所有属性都作为字符串返回。

例如,一个名为 user_id 且类型为 int(10) 的列,如果行值是 5423,在 PHP 中我们会得到一个类似 "5423" 的字符串。

这是一个历史已知错误

最佳解决方案是升级到 PHP 8.1 或更高版本。如果无法升级,Eloquent 的属性转换是次佳选择。

迁移

此驱动程序提供了许多创建或修改表的 SingleStore 特定方法。以下列出了它们。有关更多信息,请参阅 SingleStore 上的创建表文档。

通用存储表(列存储)

默认情况下,由该驱动程序创建的表将使用 SingleStoreDB Universal Storage。Universal Storage 利用列和行数据结构自动优化事务和分析工作负载的存储。通常,除非您分析了工作负载并确定其他表类型更好,否则应使用此表类型。

要创建表,您可以使用 Schema::create

Schema::create('table', function (Blueprint $table) {
    // ... column definitions, indexes, table options
});

行存储表

要创建 rowstore 表,请使用 rowstore 方法。Rowstore 表针对低延迟事务工作负载进行了优化,具有高并发性,但以内存为代价。通常,我们建议使用 Universal Storage(见上文)并在使用 rowstore 表之前基准测试您的负载。

Schema::create('table', function (Blueprint $table) {
    $table->rowstore();

    // ...
});

参考表

要创建 参考表,可以使用 reference 方法。参考表会完全复制到集群中的每个节点。这意味着如果在一个参考表中存储 1000 行,这些 1000 行将被复制多次。因此,您应该只存储少量数据在参考表中,并且仅在您需要通过与其他表的非本地数据连接来引用这些数据时使用。对参考表的插入和更新也将因为高复制开销而运行得更慢。

Schema::create('table', function (Blueprint $table) {
    $table->reference();

    // ...
});

全局临时表

要创建 全局临时表,可以在表上使用 global 方法。

Schema::create('table', function (Blueprint $table) {
    $table->rowstore();
    $table->temporary();
    $table->global();

    // ...
});

您还可以使用以下两种方法中的任何一种

// Fluent
$table->rowstore()->temporary()->global();

// As an argument to `temporary`.
$table->temporary($global = true);

稀疏列

您可以通过在列定义后追加 sparse 来流畅地标记特定列为 稀疏。这仅适用于 Rowstore 表。

Schema::create('table', function (Blueprint $table) {
    $table->rowstore();

    $table->string('name')->nullable()->sparse();
});

稀疏表

您可以通过在列定义后追加 sparse 来流畅地标记整个表为 稀疏。这仅适用于 Rowstore 表。

Schema::create('table', function (Blueprint $table) {
    $table->rowstore();

    $table->string('name');

    $table->sparse();
});

分片键

您可以使用独立的 shardKey 方法或将 shardKey 添加到列定义中,以流畅的方式为您的表添加分片键。

Schema::create('table', function (Blueprint $table) {
    $table->string('name');

    $table->shardKey('name');
});

Schema::create('table', function (Blueprint $table) {
    $table->string('name')->shardKey();
});

Schema::create('table', function (Blueprint $table) {
    $table->string('f_name');
    $table->string('l_name');

    $table->shardKey(['f_name', 'l_name']);
});

排序键

您可以使用独立的 sortKey 方法或将 sortKey 添加到列定义中,以流畅的方式为您的表添加排序键。

Schema::create('table', function (Blueprint $table) {
    $table->string('name');

    $table->sortKey('name');
});

Schema::create('table', function (Blueprint $table) {
    $table->string('name')->sortKey();
});

Schema::create('table', function (Blueprint $table) {
    $table->string('f_name');
    $table->string('l_name');

    $table->sortKey(['f_name', 'l_name']);
});

默认情况下,排序键按升序排序。如果您想创建一个按降序排序的排序键,可以将键方向设置为 desc

Schema::create('table', function (Blueprint $table) {
    $table->string('name');

    $table->sortKey('name', 'desc');
});

Schema::create('table', function (Blueprint $table) {
    $table->string('name')->sortKey('desc');
});

您还可以使用以下语法按列定义排序键方向:

Schema::create('table', function (Blueprint $table) {
    $table->string('f_name');
    $table->string('l_name');

    $table->sortKey([['f_name', 'asc'], ['l_name', 'desc']]);
});

有时您可能想要根据表调整 columnstore。您可以通过将 with 流畅地添加到 sortKey 定义中来实现。

Schema::create('table', function (Blueprint $table) {
    $table->string('name');

    $table->sortKey('name')->with(['columnstore_segment_rows' => 100000]);
});

Schema::create('table', function (Blueprint $table) {
    $table->string('name')->sortKey()->with(['columnstore_segment_rows' => 100000]);
});

但是,您可能想要在不设置列为排序键的情况下进行调整。您可以通过创建一个空的 sortKey 定义来实现。

Schema::create('table', function (Blueprint $table) {
    $table->string('name');

    $table->sortKey()->with(['columnstore_segment_rows' => 100000]);
});

唯一键

您可以使用独立的 unique 方法或将 unique 添加到列定义中,以向您的表添加唯一键。

注意 SingleStore 要求分片键包含在唯一键中。这意味着在大多数情况下,您不能使用流畅的 API,因为您可能需要指定多个列。此限制不适用于参考表。

Schema::create('table', function (Blueprint $table) {
    $table->string('key');
    $table->string('val');

    $table->shardKey('key');
    $table->unique(['key', 'val']);
});

Schema::create('table', function (Blueprint $table) {
    $table->reference();
    $table->string('name')->unique();
});

哈希键

您可以使用 index 函数的第三个参数向您的表添加哈希键。请注意,默认情况下,通用存储表(Columnstore)上的索引始终是哈希索引,因此简单的 .index(foo) 通常足够。在 Rowstore 表上需要此语法来创建哈希索引。

Schema::create('table', function (Blueprint $table) {
    $table->string('name');
    $table->index('name', 'name_idx', 'hash');
});

系列时间戳

要表示列为时间序列,请使用 seriesTimestamp 列修饰符。

Schema::create('table', function (Blueprint $table) {
    $table->datetime('created_at')->seriesTimestamp();

    // Or make it sparse
    $table->datetime('deleted_at')->nullable()->seriesTimestamp()->sparse();
});

计算列

SingleStore 不支持虚拟计算列。您必须使用 Laravel 的 storedAs 方法来创建持久计算列。

Schema::create('test', function (Blueprint $table) {
    $table->integer('a');
    $table->integer('b');
    $table->integer('c')->storedAs('a + b');
});

没有主键的递增列

有时您可能想要设置自定义主键。但是,如果您的表有一个 int increment 列,Laravel 默认始终将此列设置为主键。即使您手动设置了另一个主键也是如此。您可以使用 withoutPrimaryKey 方法禁用此行为。

Schema::create('test', function (Blueprint $table) {
    $table->id()->withoutPrimaryKey();
    $table->uuid('uuid');
    
    $table->primary(['id',  'uuid']);
});

使用FULLTEXT索引进行全文搜索

SingleStoreDB 支持在列存储表中的文本列上使用 FULLTEXT 索引类型进行全文搜索。

请注意,FULLTEXT 仅在使用 utf8_unicode_ci 校准时受支持。如果您尝试将索引添加到不支持校对的列,将抛出异常。

Schema::create('test', function (Blueprint $table) {
    $table->id();
    $table->text('first_name')->collation('utf8_unicode_ci');

    $table->fullText(['first_name']);
});

测试

使用 PHPUnit 执行测试

./vendor/bin/phpunit

要针对活动的 SingleStore 数据库进行测试,创建一个 .env 文件并填充以下变量

DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=
DB_HOST=

现在,在执行测试时,通过运行以下命令启用集成测试:

HYBRID_INTEGRATION=1 ./vendor/bin/phpunit

兼容性矩阵

许可

此库根据 Apache 2.0 许可证授权。

资源

用户协议

单店科技有限公司(以下简称“单店”)同意授予您及您的公司访问本开源软件连接器的权限,前提是(A)您及您的公司代表并保证,您作为您公司的代表,有合法权力将您公司约束于以下条款(B)您作为您公司的代表接受并同意受以下适用于本开源连接器的开源条款和条件的约束(本“协议”),此协议的最终证据可以是以下任一方式:您作为您公司的代表点击“下载”、“接受”或“继续”按钮,或者您公司安装、访问或使用开源连接器,或者使用单店提供的任何服务(包括任何更新或升级),本协议自连接器的下载、访问、复制或安装或使用任何服务的日期较早者生效。

客户理解并同意,本协议授予客户访问SingleStore开源软件连接器(“测试版软件连接器”)的权限,仅限于非生产测试和评估该测试版软件连接器。客户承认,单店没有义务发布该测试版软件连接器的通用版本,也没有义务为该测试版软件连接器提供支持或保修,除非用于生产或非评估用途。

尽管任何文档、协议或订单文件中有任何相反规定,单店对本次测试版软件连接器(包括工具和实用程序)将不提供任何保修、赔偿、支持或服务水平义务。

适用的开源许可:Apache 2.0

如果您或您的公司不同意这些条款和条件,请勿勾选接受框,并请勿下载、访问、复制、安装或使用软件或服务。