sql >> Database >  >> RDS >> MariaDB

ProxySQL 2.0 uitvoeren en configureren voor MySQL Galera Cluster op Docker

ProxySQL is een intelligente en krachtige SQL-proxy die MySQL, MariaDB en ClickHouse ondersteunt. Onlangs is ProxySQL 2.0 GA geworden en wordt het geleverd met nieuwe opwindende functies zoals GTID-consistent lezen, frontend SSL, Galera en native ondersteuning voor MySQL Group Replication.

Het is relatief eenvoudig om ProxySQL als Docker-container uit te voeren. We hebben eerder geschreven over het uitvoeren van ProxySQL op Kubernetes als een helpercontainer of als een Kubernetes-service, die is gebaseerd op ProxySQL 1.x. In deze blogpost gaan we de nieuwe versie ProxySQL 2.x gebruiken die een andere benadering gebruikt voor de configuratie van Galera Cluster.

ProxySQL 2.x Docker-afbeelding

We hebben een nieuwe ProxySQL 2.0 Docker-imagecontainer uitgebracht en deze is beschikbaar in Docker Hub. De README biedt een aantal configuratievoorbeelden, met name voor Galera en MySQL-replicatie, pre en post v2.x. De configuratieregels kunnen worden gedefinieerd in een tekstbestand en worden toegewezen aan het pad van de container op /etc/proxysql.cnf om te worden geladen in de ProxySQL-service.

De afbeelding "laatste" tag wijst nog steeds naar 1.x totdat ProxySQL 2.0 officieel GA wordt (we hebben nog geen officiële releaseblog/artikel van het ProxySQL-team gezien). Dat betekent dat wanneer je ProxySQL-image installeert met de nieuwste tag van Verschillend, je er nog steeds versie 1.x bij krijgt. Let op:de nieuwe voorbeeldconfiguraties maken ook ProxySQL-webstatistieken mogelijk (geïntroduceerd in 1.4.4 maar nog steeds in bèta) - een eenvoudig dashboard dat de algehele configuratie en status van ProxySQL zelf samenvat.

ProxySQL 2.x-ondersteuning voor Galera-cluster

Laten we het in meer detail hebben over de native ondersteuning van Galera Cluster. De nieuwe tabel mysql_galera_hostgroups bestaat uit de volgende velden:

  • writer_hostgroup : ID van de hostgroep die alle leden zal bevatten die schrijvers zijn (read_only=0).
  • backup_writer_hostgroup : Als het cluster wordt uitgevoerd in de modus voor meerdere schrijvers (d.w.z. er zijn meerdere knooppunten met alleen-lezen =0) en max_writers is ingesteld op een kleiner aantal dan het totale aantal knooppunten, worden de extra knooppunten verplaatst naar deze back-upschrijverhostgroep.
  • reader_hostgroup : ID van de hostgroep die alle leden zal bevatten die lezers zijn (d.w.z. knooppunten met read_only=1)
  • offline_hostgroep : Wanneer ProxySQL-bewaking bepaalt dat een host OFFLINE is, wordt de host verplaatst naar de offline_hostgroep.
  • actief : een booleaanse waarde (0 of 1) om een ​​hostgroep te activeren
  • max_writers : Regelt het maximum aantal toegestane knooppunten in de writer-hostgroep, zoals eerder vermeld, zullen extra knooppunten worden verplaatst naar de backup_writer_hostgroup.
  • writer_is_also_reader : Bij 1 wordt een node in de writer_hostgroup ook in de reader_hostgroup geplaatst zodat deze voor reads wordt gebruikt. Indien ingesteld op 2, worden de nodes van backup_writer_hostgroup in de reader_hostgroup geplaatst in plaats van de node(s) in de writer_hostgroup.
  • max_transactions_behind : bepaalt het maximale aantal schrijfsets dat een knooppunt in het cluster in de wachtrij kan hebben staan ​​voordat het knooppunt wordt UITGESCHAKELD om verouderde leesbewerkingen te voorkomen (dit wordt bepaald door een query uit te voeren op de variabele wsrep_local_recv_queue Galera).
  • commentaar : Tekstveld dat kan worden gebruikt voor alle door de gebruiker gedefinieerde doeleinden

Hier is een voorbeeldconfiguratie voor mysql_galera_hostgroups in tabelformaat:

Admin> select * from mysql_galera_hostgroups\G
*************************** 1. row ***************************
       writer_hostgroup: 10
backup_writer_hostgroup: 20
       reader_hostgroup: 30
      offline_hostgroup: 9999
                 active: 1
            max_writers: 1
  writer_is_also_reader: 2
max_transactions_behind: 20
                comment: 

ProxySQL voert Galera-gezondheidscontroles uit door de volgende MySQL-status/variabele te bewaken:

  • alleen-lezen - Indien AAN, zal ProxySQL de gedefinieerde host groeperen in reader_hostgroup tenzij writer_is_also_reader 1 is.
  • wsrep_desync - Indien AAN, zal ProxySQL het knooppunt markeren als niet beschikbaar en verplaatsen naar offline_hostgroup.
  • wsrep_reject_queries - Als deze variabele AAN staat, zal ProxySQL het knooppunt markeren als niet beschikbaar en verplaatsen naar de offline_hostgroep (handig in bepaalde onderhoudssituaties).
  • wsrep_sst_donor_rejects_queries - Als deze variabele AAN staat, zal ProxySQL het knooppunt markeren als niet beschikbaar terwijl het Galera-knooppunt dienst doet als SST-donor, en wordt het verplaatst naar de offline_hostgroep.
  • wsrep_local_state - Als deze status een andere dan 4 retourneert (4 betekent gesynchroniseerd), markeert ProxySQL het knooppunt als niet beschikbaar en verplaatst het naar offline_hostgroup.
  • wsrep_local_recv_queue - Als deze status hoger is dan max_transactions_behind, wordt de node gemeden.
  • wsrep_cluster_status - Als deze status een andere dan Primair retourneert, markeert ProxySQL het knooppunt als niet beschikbaar en verplaatst het naar offline_hostgroup.

Dat gezegd hebbende, heeft ProxySQL 2.x, door deze nieuwe parameters in mysql_galera_hostgroups te combineren met mysql_query_rules, de flexibiliteit om in veel meer Galera-gebruiksgevallen te passen. Men kan bijvoorbeeld een hostgroep met één schrijver, meerdere schrijvers en meerdere lezers hebben gedefinieerd als de doelhostgroep van een queryregel, met de mogelijkheid om het aantal schrijvers te beperken en fijner controle over het verouderde leesgedrag.

Vergelijk dit met ProxySQL 1.x, waar de gebruiker expliciet een planner moest definiëren om een ​​extern script aan te roepen om de backend-statuscontroles uit te voeren en de status van de databaseservers bij te werken. Dit vereist enige aanpassing aan het script (de gebruiker moet de ProxySQL-beheerdersgebruiker/wachtwoord/poort bijwerken) en het was afhankelijk van een extra tool (MySQL-client) om verbinding te maken met de ProxySQL-beheerdersinterface.

Hier is een voorbeeldconfiguratie van Galera Health Check-scriptplanner in tabelformaat voor ProxySQL 1.x:

Admin> select * from scheduler\G
*************************** 1. row ***************************
         id: 1
     active: 1
interval_ms: 2000
   filename: /usr/share/proxysql/tools/proxysql_galera_checker.sh
       arg1: 10
       arg2: 20
       arg3: 1
       arg4: 1
       arg5: /var/lib/proxysql/proxysql_galera_checker.log
    comment:

Bovendien, aangezien ProxySQL-plannerthread elk script onafhankelijk uitvoert, zijn er veel versies van gezondheidscontrolescripts beschikbaar. Alle ProxySQL-instanties die door ClusterControl worden geïmplementeerd, gebruiken het standaardscript dat wordt geleverd door het ProxySQL-installatiepakket.

In ProxySQL 2.x kunnen max_writers en writer_is_also_reader-variabelen bepalen hoe ProxySQL de backend MySQL-servers dynamisch groepeert en rechtstreeks van invloed is op de verbindingsdistributie en queryrouting. Denk bijvoorbeeld aan de volgende MySQL-backendservers:

Admin> select hostgroup_id, hostname, status, weight from mysql_servers;
+--------------+--------------+--------+--------+
| hostgroup_id | hostname     | status | weight |
+--------------+--------------+--------+--------+
| 10           | DB1          | ONLINE | 1      |
| 10           | DB2          | ONLINE | 1      |
| 10           | DB3          | ONLINE | 1      |
+--------------+--------------+--------+--------+

Samen met de volgende definitie van Galera-hostgroepen:

Admin> select * from mysql_galera_hostgroups\G
*************************** 1. row ***************************
       writer_hostgroup: 10
backup_writer_hostgroup: 20
       reader_hostgroup: 30
      offline_hostgroup: 9999
                 active: 1
            max_writers: 1
  writer_is_also_reader: 2
max_transactions_behind: 20
                comment: 

Aangezien alle hosts actief zijn, zal ProxySQL de hosts hoogstwaarschijnlijk als volgt groeperen:

Laten we ze een voor een bekijken:

Configuratie Beschrijving
writer_is_also_reader=0
  • Groept de hosts in 2 hostgroepen (writer en backup_writer).
  • Writer maakt deel uit van de backup_writer.
  • Omdat de schrijver geen lezer is, niets in hostgroep 30 (lezer) omdat geen van de hosts is ingesteld op read_only=1. Het is niet gebruikelijk in Galera om de alleen-lezen vlag in te schakelen.
writer_is_also_reader=1
  • Groept de hosts in 3 hostgroepen (writer, backup_writer en reader).
  • Variabele read_only=0 in Galera heeft geen effect, dus schrijver zit ook in hostgroep 30 (lezer)
  • Writer maakt geen deel uit van backup_writer.
writer_is_also_reader=2
  • Vergelijkbaar met writer_is_also_reader=1 maakt writer echter deel uit van backup_writer.

Met deze configuratie kan men verschillende keuzes hebben voor hostgroepbestemmingen om tegemoet te komen aan specifieke workloads. "Hotspot"-schrijfbewerkingen kunnen worden geconfigureerd om naar slechts één server te gaan om multi-masterconflicten te verminderen, niet-conflicterende schrijfacties kunnen gelijkelijk worden verdeeld over de andere masters, de meeste leesbewerkingen kunnen gelijkmatig worden verdeeld over alle MySQL-servers of niet-schrijvers, kritieke leesbewerkingen kunnen worden doorgestuurd naar de meest up-to-date servers en analytische uitlezingen kunnen worden doorgestuurd naar een slave-replica.

ProxySQL-implementatie voor Galera-cluster

Stel dat we in dit voorbeeld al een Galera-cluster met drie knooppunten hebben geïmplementeerd door ClusterControl, zoals weergegeven in het volgende diagram:

Onze Wordpress-applicaties draaien op Docker, terwijl de Wordpress-database wordt gehost op onze Galera-cluster die draait op bare-metal servers. We hebben besloten om naast onze Wordpress-containers een ProxySQL-container te gebruiken om een ​​betere controle te hebben over de routering van zoekopdrachten in de Wordpress-database en om onze databaseclusterinfrastructuur volledig te benutten. Aangezien de lees-schrijfverhouding ongeveer 80%-20% is, willen we ProxySQL configureren om:

  • Stuur alle schrijfbewerkingen door naar één Galera-knooppunt (minder conflicten, focus op schrijven)
  • Verdeel alle leesbewerkingen naar de andere twee Galera-knooppunten (betere verdeling voor het grootste deel van de werklast)

Maak eerst een ProxySQL-configuratiebestand in de Docker-host zodat we het in onze container kunnen mappen:

$ mkdir /root/proxysql-docker
$ vim /root/proxysql-docker/proxysql.cnf

Kopieer dan de volgende regels (we zullen de configuratieregels verderop uitleggen):

datadir="/var/lib/proxysql"

admin_variables=
{
    admin_credentials="admin:admin"
    mysql_ifaces="0.0.0.0:6032"
    refresh_interval=2000
    web_enabled=true
    web_port=6080
    stats_credentials="stats:admin"
}

mysql_variables=
{
    threads=4
    max_connections=2048
    default_query_delay=0
    default_query_timeout=36000000
    have_compress=true
    poll_timeout=2000
    interfaces="0.0.0.0:6033;/tmp/proxysql.sock"
    default_schema="information_schema"
    stacksize=1048576
    server_version="5.1.30"
    connect_timeout_server=10000
    monitor_history=60000
    monitor_connect_interval=200000
    monitor_ping_interval=200000
    ping_interval_server_msec=10000
    ping_timeout_server=200
    commands_stats=true
    sessions_sort=true
    monitor_username="proxysql"
    monitor_password="proxysqlpassword"
    monitor_galera_healthcheck_interval=2000
    monitor_galera_healthcheck_timeout=800
}

mysql_galera_hostgroups =
(
    {
        writer_hostgroup=10
        backup_writer_hostgroup=20
        reader_hostgroup=30
        offline_hostgroup=9999
        max_writers=1
        writer_is_also_reader=1
        max_transactions_behind=30
        active=1
    }
)

mysql_servers =
(
    { address="db1.cluster.local" , port=3306 , hostgroup=10, max_connections=100 },
    { address="db2.cluster.local" , port=3306 , hostgroup=10, max_connections=100 },
    { address="db3.cluster.local" , port=3306 , hostgroup=10, max_connections=100 }
)

mysql_query_rules =
(
    {
        rule_id=100
        active=1
        match_pattern="^SELECT .* FOR UPDATE"
        destination_hostgroup=10
        apply=1
    },
    {
        rule_id=200
        active=1
        match_pattern="^SELECT .*"
        destination_hostgroup=30
        apply=1
    },
    {
        rule_id=300
        active=1
        match_pattern=".*"
        destination_hostgroup=10
        apply=1
    }
)

mysql_users =
(
    { username = "wordpress", password = "passw0rd", default_hostgroup = 10, transaction_persistent = 0, active = 1 },
    { username = "sbtest", password = "passw0rd", default_hostgroup = 10, transaction_persistent = 0, active = 1 }
)

Laten we nu een bezoek brengen aan enkele van de meeste configuratiesecties. Ten eerste definiëren we de configuratie van Galera-hostgroepen zoals hieronder:

mysql_galera_hostgroups =
(
    {
        writer_hostgroup=10
        backup_writer_hostgroup=20
        reader_hostgroup=30
        offline_hostgroup=9999
        max_writers=1
        writer_is_also_reader=1
        max_transactions_behind=30
        active=1
    }
)

Hostgroep 10 is de writer_hostgroup, hostgroup 20 voor backup_writer en hostgroep 30 voor reader. We stellen max_writers in op 1 zodat we een hostgroep met één schrijver kunnen hebben voor hostgroep 10 waar alle schrijfbewerkingen naartoe moeten worden gestuurd. Vervolgens definiëren we writer_is_also_reader op 1, waardoor alle Galera-knooppunten ook als lezer worden gebruikt, geschikt voor query's die gelijkelijk over alle knooppunten kunnen worden verdeeld. Hostgroup 9999 is gereserveerd voor offline_hostgroup als ProxySQL niet-operationele Galera-knooppunten detecteert.

Vervolgens configureren we onze MySQL-servers standaard op hostgroep 10:

mysql_servers =
(
    { address="db1.cluster.local" , port=3306 , hostgroup=10, max_connections=100 },
    { address="db2.cluster.local" , port=3306 , hostgroup=10, max_connections=100 },
    { address="db3.cluster.local" , port=3306 , hostgroup=10, max_connections=100 }
)

Met de bovenstaande configuraties "ziet" ProxySQL onze hostgroepen zoals hieronder:

Vervolgens definiëren we de queryroutering via queryregels. Op basis van onze vereisten moeten alle leesbewerkingen worden verzonden naar alle Galera-knooppunten behalve de schrijver (hostgroep 20) en al het andere wordt doorgestuurd naar hostgroep 10 voor enkele schrijver:

mysql_query_rules =
(
    {
        rule_id=100
        active=1
        match_pattern="^SELECT .* FOR UPDATE"
        destination_hostgroup=10
        apply=1
    },
    {
        rule_id=200
        active=1
        match_pattern="^SELECT .*"
        destination_hostgroup=20
        apply=1
    },
    {
        rule_id=300
        active=1
        match_pattern=".*"
        destination_hostgroup=10
        apply=1
    }
)

Ten slotte definiëren we de MySQL-gebruikers die door ProxySQL zullen worden doorgegeven:

mysql_users =
(
    { username = "wordpress", password = "passw0rd", default_hostgroup = 10, transaction_persistent = 0, active = 1 },
    { username = "sbtest", password = "passw0rd", default_hostgroup = 10, transaction_persistent = 0, active = 1 }
)

We hebben transaction_persistent op 0 gezet, zodat alle verbindingen die van deze gebruikers komen, de queryregels voor lees- en schrijfroutering respecteren. Anders zouden de verbindingen uiteindelijk één hostgroep raken, wat het doel van taakverdeling tenietdoet. Vergeet niet om die gebruikers eerst aan te maken op alle MySQL-servers. Voor gebruikers van ClusterControl kunt u de functie Beheren -> Schema's en gebruikers gebruiken om die gebruikers aan te maken.

We zijn nu klaar om onze container te starten. We gaan het ProxySQL-configuratiebestand als bind mount toewijzen bij het opstarten van de ProxySQL-container. Het run-commando zal dus zijn:

$ docker run -d \
--name proxysql2 \
--hostname proxysql2 \
--publish 6033:6033 \
--publish 6032:6032 \
--publish 6080:6080 \
--restart=unless-stopped \
-v /root/proxysql/proxysql.cnf:/etc/proxysql.cnf \
severalnines/proxysql:2.0

Wijzig ten slotte de Wordpress-database die verwijst naar ProxySQL-containerpoort 6033, bijvoorbeeld:

$ docker run -d \
--name wordpress \
--publish 80:80 \
--restart=unless-stopped \
-e WORDPRESS_DB_HOST=proxysql2:6033 \
-e WORDPRESS_DB_USER=wordpress \
-e WORDPRESS_DB_HOST=passw0rd \
wordpress

Op dit moment ziet onze architectuur er ongeveer zo uit:

Als u wilt dat de ProxySQL-container persistent is, wijst u /var/lib/proxysql/ toe aan een Docker-volume of bindt u een koppeling, bijvoorbeeld:

$ docker run -d \
--name proxysql2 \
--hostname proxysql2 \
--publish 6033:6033 \
--publish 6032:6032 \
--publish 6080:6080 \
--restart=unless-stopped \
-v /root/proxysql/proxysql.cnf:/etc/proxysql.cnf \
-v proxysql-volume:/var/lib/proxysql \
severalnines/proxysql:2.0

Houd er rekening mee dat het draaien met permanente opslag zoals hierboven onze /root/proxysql/proxysql.cnf bij de tweede herstart overbodig maakt. Dit komt door de meerlaagse ProxySQL-configuratie waarbij als /var/lib/proxysql/proxysql.db bestaat, ProxySQL de laadopties van het configuratiebestand overslaat en in plaats daarvan laadt wat zich in de SQLite-database bevindt (tenzij u de proxysql-service start met --initial vlag). Dat gezegd hebbende, moet het volgende ProxySQL-configuratiebeheer worden uitgevoerd via de ProxySQL-beheerconsole op poort 6032, in plaats van het configuratiebestand te gebruiken.

Bewaking

ProxySQL-proceslogboek logt standaard in op syslog en u kunt ze bekijken met het standaard docker-commando:

$ docker ps
$ docker logs proxysql2

Om de huidige hostgroep te verifiëren, voert u een query uit in de tabel runtime_mysql_servers:

$ docker exec -it proxysql2 mysql -uadmin -padmin -h127.0.0.1 -P6032 --prompt='Admin> '
Admin> select hostgroup_id,hostname,status from runtime_mysql_servers;
+--------------+--------------+--------+
| hostgroup_id | hostname     | status |
+--------------+--------------+--------+
| 10           | 192.168.0.21 | ONLINE |
| 30           | 192.168.0.21 | ONLINE |
| 30           | 192.168.0.22 | ONLINE |
| 30           | 192.168.0.23 | ONLINE |
| 20           | 192.168.0.22 | ONLINE |
| 20           | 192.168.0.23 | ONLINE |
+--------------+--------------+--------+

Als de geselecteerde schrijver uitvalt, wordt deze overgebracht naar de offline_hostgroep (HID 9999):

Admin> select hostgroup_id,hostname,status from runtime_mysql_servers;
+--------------+--------------+--------+
| hostgroup_id | hostname     | status |
+--------------+--------------+--------+
| 10           | 192.168.0.22 | ONLINE |
| 9999         | 192.168.0.21 | ONLINE |
| 30           | 192.168.0.22 | ONLINE |
| 30           | 192.168.0.23 | ONLINE |
| 20           | 192.168.0.23 | ONLINE |
+--------------+--------------+--------+

De bovenstaande veranderingen in de topologie kunnen worden geïllustreerd in het volgende diagram:

We hebben ook de gebruikersinterface voor webstatistieken ingeschakeld met admin-web_enabled=true. Om toegang te krijgen tot de webinterface, gaat u gewoon naar de Docker-host in poort 6080, bijvoorbeeld:http://192.168.0.200:8060 en u wordt gevraagd met een gebruikersnaam/wachtwoord pop-up. Voer de inloggegevens in zoals gedefinieerd onder admin-stats_credentials en u zou de volgende pagina moeten zien:

Door de MySQL-verbindingspooltabel te bewaken, kunnen we een overzicht van de verbindingsdistributie krijgen voor alle hostgroepen:

Admin> select hostgroup, srv_host, status, ConnUsed, MaxConnUsed, Queries from stats.stats_mysql_connection_pool order by srv_host;
+-----------+--------------+--------+----------+-------------+---------+
| hostgroup | srv_host     | status | ConnUsed | MaxConnUsed | Queries |
+-----------+--------------+--------+----------+-------------+---------+
| 20        | 192.168.0.23 | ONLINE | 5        | 24          | 11458   |
| 30        | 192.168.0.23 | ONLINE | 0        | 0           | 0       |
| 20        | 192.168.0.22 | ONLINE | 2        | 24          | 11485   |
| 30        | 192.168.0.22 | ONLINE | 0        | 0           | 0       |
| 10        | 192.168.0.21 | ONLINE | 32       | 32          | 9746    |
| 30        | 192.168.0.21 | ONLINE | 0        | 0           | 0       |
+-----------+--------------+--------+----------+-------------+---------+

De uitvoer hierboven laat zien dat hostgroep 30 niets verwerkt omdat onze queryregels deze hostgroep niet hebben geconfigureerd als bestemmingshostgroep.

De statistieken met betrekking tot de Galera-knooppunten kunnen worden bekeken in de mysql_server_galera_log-tabel:

Admin>  select * from mysql_server_galera_log order by time_start_us desc limit 3\G
*************************** 1. row ***************************
                       hostname: 192.168.0.23
                           port: 3306
                  time_start_us: 1552992553332489
                success_time_us: 2045
              primary_partition: YES
                      read_only: NO
         wsrep_local_recv_queue: 0
              wsrep_local_state: 4
                   wsrep_desync: NO
           wsrep_reject_queries: NO
wsrep_sst_donor_rejects_queries: NO
                          error: NULL
*************************** 2. row ***************************
                       hostname: 192.168.0.22
                           port: 3306
                  time_start_us: 1552992553329653
                success_time_us: 2799
              primary_partition: YES
                      read_only: NO
         wsrep_local_recv_queue: 0
              wsrep_local_state: 4
                   wsrep_desync: NO
           wsrep_reject_queries: NO
wsrep_sst_donor_rejects_queries: NO
                          error: NULL
*************************** 3. row ***************************
                       hostname: 192.168.0.21
                           port: 3306
                  time_start_us: 1552992553329013
                success_time_us: 2715
              primary_partition: YES
                      read_only: NO
         wsrep_local_recv_queue: 0
              wsrep_local_state: 4
                   wsrep_desync: NO
           wsrep_reject_queries: NO
wsrep_sst_donor_rejects_queries: NO
                          error: NULL

De resultatenset retourneert de gerelateerde MySQL-variabele/statusstatus voor elk Galera-knooppunt voor een bepaald tijdstempel. In deze configuratie hebben we de Galera-gezondheidscontrole zo geconfigureerd dat deze elke 2 seconden wordt uitgevoerd (monitor_galera_healthcheck_interval=2000). Daarom zou de maximale failover-tijd ongeveer 2 seconden zijn als er een topologiewijziging plaatsvindt in het cluster.

Referenties

  • ProxySQL Native Galera-ondersteuning
  • HA- en clusteroplossing:ProxySQL als intelligente router voor Galera en groepsreplicatie
  • ProxySQL Docker-afbeelding door Multiplenines
  • Hoe ProxySQL te controleren met Prometheus en ClusterControl

  1. ORA-04021:time-out opgetreden tijdens het wachten om object te vergrendelen

  2. Navicat voor MySQL

  3. Hoe vind ik Unicode/niet-ASCII-tekens in een NTEXT-veld in een SQL Server 2005-tabel?

  4. Gegevens invoegen in tabellen die zijn gekoppeld door een externe sleutel